Cleanup config.nodes_of
[check_mk.git] / cmk_base / core.py
blob4ce654d84ecdb7584050883ebb6d83809618862e
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
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"""
28 import fcntl
29 import os
30 import subprocess
31 import sys
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-------------------------------------------------------------.
52 # | ____ _ _ |
53 # | / ___|___ _ __ | |_ _ __ ___ | | |
54 # | | | / _ \| '_ \| __| '__/ _ \| | |
55 # | | |__| (_) | | | | |_| | | (_) | | |
56 # | \____\___/|_| |_|\__|_| \___/|_| |
57 # | |
58 # +----------------------------------------------------------------------+
59 # | Invoke actions affecting the core like reload/restart |
60 # '----------------------------------------------------------------------'
63 def do_reload(core):
64 do_restart(core, only_reload=True)
67 # TODO: Cleanup duplicate code with automation_restart()
68 def do_restart(core, only_reload=False):
69 try:
70 backup_path = None
72 if try_get_activation_lock():
73 # TODO: Replace by MKBailOut()/MKTerminate()?
74 console.error("Other restart currently in progress. Aborting.\n")
75 sys.exit(1)
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"
80 console.verbose(
81 "Renaming %s to %s\n",
82 cmk.utils.paths.nagios_objects_file,
83 backup_path,
84 stream=sys.stderr)
85 os.rename(cmk.utils.paths.nagios_objects_file, backup_path)
86 else:
87 backup_path = None
89 try:
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)
94 if backup_path:
95 os.rename(backup_path, cmk.utils.paths.nagios_objects_file)
96 if cmk.utils.debug.enabled():
97 raise
98 sys.exit(1)
100 if config.monitoring_core == "cmc" or cmk_base.nagios_utils.do_check_nagiosconfig():
101 if backup_path:
102 os.remove(backup_path)
104 core.precompile()
106 do_core_action(only_reload and "reload" or "restart")
107 else:
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())
113 console.error(
114 "The broken file has been copied to \"%s\" for analysis.\n" % broken_config_path)
116 if backup_path:
117 os.rename(backup_path, cmk.utils.paths.nagios_objects_file)
118 else:
119 os.remove(cmk.utils.paths.nagios_objects_file)
120 sys.exit(1)
122 except Exception as e:
123 try:
124 if backup_path and os.path.exists(backup_path):
125 os.remove(backup_path)
126 except:
127 pass
128 if cmk.utils.debug.enabled():
129 raise
130 # TODO: Replace by MKBailOut()/MKTerminate()?
131 console.error("An error occurred: %s\n" % e)
132 sys.exit(1)
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)
143 try:
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))
147 except:
148 return True
149 return False
152 # Action can be restart, reload, start or stop
153 def do_core_action(action, quiet=False):
154 if not quiet:
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]
160 else:
161 command = ["omd", action, "cmc"]
163 p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
164 result = p.wait()
165 if result != 0:
166 output = p.stdout.read()
167 if not quiet:
168 console.output("ERROR: %s\n" % output)
169 raise MKGeneralException("Cannot %s the monitoring core: %s" % (action, output))
170 else:
171 if not quiet:
172 console.output(tty.ok + "\n")
176 # .--Timeperiods---------------------------------------------------------.
177 # | _____ _ _ _ |
178 # | |_ _(_)_ __ ___ ___ _ __ ___ _ __(_) ___ __| |___ |
179 # | | | | | '_ ` _ \ / _ \ '_ \ / _ \ '__| |/ _ \ / _` / __| |
180 # | | | | | | | | | | __/ |_) | __/ | | | (_) | (_| \__ \ |
181 # | |_| |_|_| |_| |_|\___| .__/ \___|_| |_|\___/ \__,_|___/ |
182 # | |_| |
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.
193 try:
194 update_timeperiods_cache()
195 except MKTimeout:
196 raise
198 except:
199 if cmk.utils.debug.enabled():
200 raise
202 # If the query is not successful better skip this check then fail
203 return True
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)
210 # Returns
211 # True : active
212 # False: inactive
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")
227 if not tp_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)