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 """Settings handling for the Check_MK event console."""
28 from __future__
import print_function
30 # For some background about various design decisions below, see the concise
31 # but excellent article "Parsing Command Line Arguments" in the FPComplete blog
32 # at https://www.fpcomplete.com/blog/2017/12/parsing-command-line-arguments.
34 # NOTE: pylint/astroid doesn't fully understand typing annotations and the
35 # typing module yet, so we may have to suppress some things, see e.g. the
36 # issues https://github.com/PyCQA/pylint/issues/1063 for unused-import and
37 # https://github.com/PyCQA/pylint/issues/1290 for invalid-name.
39 from argparse
import ArgumentParser
, ArgumentTypeError
, RawDescriptionHelpFormatter
40 from typing
import List
, NamedTuple
, Optional
, Union
# pylint: disable=unused-import
42 from pathlib2
import Path
44 # a filesystem path with a user-presentable description
45 AnnotatedPath
= NamedTuple('AnnotatedPath', [('description', str), ('value', Path
)])
47 # filesystem paths related to the event console
48 Paths
= NamedTuple('Paths', [
49 ('main_config_file', AnnotatedPath
),
50 ('config_dir', AnnotatedPath
),
51 ('rule_pack_dir', AnnotatedPath
),
52 ('mkp_rule_pack_dir', AnnotatedPath
),
53 ('unix_socket', AnnotatedPath
),
54 ('event_socket', AnnotatedPath
),
55 ('event_pipe', AnnotatedPath
),
56 ('pid_file', AnnotatedPath
),
57 ('log_file', AnnotatedPath
),
58 ('history_dir', AnnotatedPath
),
59 ('messages_dir', AnnotatedPath
),
60 ('master_config_file', AnnotatedPath
),
61 ('slave_status_file', AnnotatedPath
),
62 ('spool_dir', AnnotatedPath
),
63 ('status_file', AnnotatedPath
),
64 ('status_server_profile', AnnotatedPath
),
65 ('event_server_profile', AnnotatedPath
),
66 ('compiled_mibs_dir', AnnotatedPath
),
67 ('mongodb_config_file', AnnotatedPath
),
71 def _default_paths(omd_root
, default_config_dir
):
72 # type: (Path, Path) -> Paths
73 """Returns all default filesystem paths related to the event console"""
74 run_dir
= omd_root
/ 'tmp/run/mkeventd'
75 state_dir
= omd_root
/ 'var/mkeventd'
77 main_config_file
=AnnotatedPath('main configuration', default_config_dir
/ 'mkeventd.mk'),
78 config_dir
=AnnotatedPath('configuration directory', default_config_dir
/ 'mkeventd.d'),
79 rule_pack_dir
=AnnotatedPath('rule pack directory',
80 default_config_dir
/ 'mkeventd.d' / 'wato'),
81 mkp_rule_pack_dir
=AnnotatedPath('rule pack export directory',
82 default_config_dir
/ 'mkeventd.d' / 'mkp' / 'rule_packs'),
83 unix_socket
=AnnotatedPath('Unix socket', run_dir
/ 'status'),
84 event_socket
=AnnotatedPath('event socket', run_dir
/ 'eventsocket'),
85 event_pipe
=AnnotatedPath('event pipe', run_dir
/ 'events'),
86 pid_file
=AnnotatedPath('PID file', run_dir
/ 'pid'),
87 log_file
=AnnotatedPath('log file', omd_root
/ 'var/log/mkeventd.log'),
88 history_dir
=AnnotatedPath('history directory', state_dir
/ 'history'),
89 messages_dir
=AnnotatedPath('messages directory', state_dir
/ 'messages'),
90 master_config_file
=AnnotatedPath('master configuraion', state_dir
/ 'master_config'),
91 slave_status_file
=AnnotatedPath('slave status', state_dir
/ 'slave_status'),
92 spool_dir
=AnnotatedPath('spool directory', state_dir
/ 'spool'),
93 status_file
=AnnotatedPath('status file', state_dir
/ 'status'),
94 status_server_profile
=AnnotatedPath('status server profile',
95 state_dir
/ 'StatusServer.profile'),
96 event_server_profile
=AnnotatedPath('event server profile',
97 state_dir
/ 'EventServer.profile'),
98 compiled_mibs_dir
=AnnotatedPath('compiled MIBs directory',
99 omd_root
/ 'local/share/check_mk/compiled_mibs'),
100 mongodb_config_file
=AnnotatedPath('MongoDB configuration', omd_root
/ 'etc/mongodb.conf'))
103 # a network port number
104 PortNumber
= NamedTuple('PortNumber', [('value', int)])
106 # network port numbers related to the event console
107 PortNumbers
= NamedTuple('PortNumbers', [
108 ('syslog_udp', PortNumber
),
109 ('syslog_tcp', PortNumber
),
110 ('snmptrap_udp', PortNumber
),
114 def _default_port_numbers():
115 # type: () -> PortNumbers
116 """Returns all port numbers related to the event console"""
118 syslog_udp
=PortNumber(514), syslog_tcp
=PortNumber(514), snmptrap_udp
=PortNumber(162))
121 # a Unix file descriptor number
122 FileDescriptor
= NamedTuple('FileDescriptor', [('value', int)])
125 class ECArgumentParser(ArgumentParser
):
126 """An argument parser for the event console"""
128 def __init__(self
, prog
, version
, paths
, port_numbers
):
129 # type: (str, str, Paths, PortNumbers) -> None
130 super(ECArgumentParser
, self
).__init
__(
132 formatter_class
=RawDescriptionHelpFormatter
,
133 description
='Start the Check_MK event console.',
134 epilog
=self
._epilog
(paths
))
135 self
._add
_arguments
(version
, port_numbers
)
139 # type: (Paths) -> str
140 width
= max([len(p
.description
) for p
in paths
]) + 1 # for colon
141 return ('Paths used by the event console:\n\n' + '\n'.join(
142 ' {:<{width}} {}'.format(p
.description
+ ':', p
.value
, width
=width
) for p
in paths
))
144 def _add_arguments(self
, version
, port_numbers
):
145 # type: (str, PortNumbers) -> None
147 '-V', '--version', action
='version', version
='%(prog)s version ' + version
)
148 self
.add_argument('-v', '--verbose', action
='count', default
=0, help='increase verbosity')
149 self
.add_argument('--syslog', action
='store_true', help='enable built-in UDP syslog server')
153 type=self
._file
_descriptor
,
154 help=('use the given file descriptor instead of UDP port %d' %
155 port_numbers
.syslog_udp
.value
))
157 '--syslog-tcp', action
='store_true', help='enable built-in TCP syslog server')
161 type=self
._file
_descriptor
,
162 help=('use the given file descriptor instead of TCP port %d' %
163 port_numbers
.syslog_tcp
.value
))
164 self
.add_argument('--snmptrap', action
='store_true', help='enable built-in snmptrap server')
168 type=self
._file
_descriptor
,
169 help=('use the given file descriptor instead of UDP port %d' %
170 port_numbers
.snmptrap_udp
.value
))
175 help='run in the foreground instead of daemonizing')
180 help='enable debug mode, letting exceptions through')
184 help='create performance profile for status thread')
188 help='create performance profile for event thread')
191 def _file_descriptor(value
):
192 # type: (str) -> FileDescriptor
193 """A custom argument type for file descriptors, i.e. non-negative integers"""
195 file_desc
= int(value
)
199 raise ArgumentTypeError('invalid file descriptor value: %r' % value
)
200 return FileDescriptor(file_desc
)
203 # a communication endpoint, e.g. for syslog or SNMP
204 EndPoint
= Union
[PortNumber
, FileDescriptor
] # pylint: disable=invalid-name
207 def _endpoint(enabled
, file_descriptor
, default_port_number
):
208 # type: (bool, FileDescriptor, PortNumber) -> Optional[EndPoint]
209 """Returns a communication endpoint based on given commandline arguments"""
212 if file_descriptor
is None:
213 return default_port_number
214 return file_descriptor
217 # various post-processed commandline options
218 Options
= NamedTuple('Options', [
220 ('syslog_udp', Optional
[EndPoint
]),
221 ('syslog_tcp', Optional
[EndPoint
]),
222 ('snmptrap_udp', Optional
[EndPoint
]),
223 ('foreground', bool),
225 ('profile_status', bool),
226 ('profile_event', bool),
229 # all settings of the event console
230 Settings
= NamedTuple('Settings', [
232 ('options', Options
),
236 def settings(version
, omd_root
, default_config_dir
, argv
):
237 # type: (str, Path, Path, List[str]) -> Settings
238 """Returns all event console settings"""
239 paths
= _default_paths(omd_root
, default_config_dir
)
240 port_numbers
= _default_port_numbers()
241 parser
= ECArgumentParser(Path(argv
[0]).name
, version
, paths
, port_numbers
)
242 args
= parser
.parse_args(argv
[1:])
244 verbosity
=args
.verbose
,
245 syslog_udp
=_endpoint(args
.syslog
, args
.syslog_fd
, port_numbers
.syslog_udp
),
246 syslog_tcp
=_endpoint(args
.syslog_tcp
, args
.syslog_tcp_fd
, port_numbers
.syslog_tcp
),
247 snmptrap_udp
=_endpoint(args
.snmptrap
, args
.snmptrap_fd
, port_numbers
.snmptrap_udp
),
248 foreground
=args
.foreground
,
250 profile_status
=args
.profile_status
,
251 profile_event
=args
.profile_event
)
252 return Settings(paths
=paths
, options
=options
)
255 if __name__
== "__main__":
258 import cmk
.utils
.paths
259 print(settings(cmk
.__version
__, Path(cmk
.utils
.paths
.omd_root
),
260 Path(cmk
.utils
.paths
.default_config_dir
), sys
.argv
))