Merge branch 'master' of ssh://lausser,shinken@shinken.git.sourceforge.net/gitroot...
[shinken.git] / setup.py
blob71f86b32d35a753861a4ff25f2369da9d900c8c1
1 #!/usr/bin/env python
2 #Copyright (C) 2009-2011 :
3 # Gabes Jean, naparuba@gmail.com
4 # Gerhard Lausser, Gerhard.Lausser@consol.de
5 # Hartmut Goebel <h.goebel@goebel-consult.de>
6 #First version of this file from Maximilien Bersoult
8 #This file is part of Shinken.
10 #Shinken is free software: you can redistribute it and/or modify
11 #it under the terms of the GNU Affero General Public License as published by
12 #the Free Software Foundation, either version 3 of the License, or
13 #(at your option) any later version.
15 #Shinken is distributed in the hope that it will be useful,
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 #GNU Affero General Public License for more details.
20 #You should have received a copy of the GNU Affero General Public License
21 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
24 # Shinken requires Python 2.4, but does not support Python 3.x yet.
25 import sys
26 try:
27 python_version = sys.version_info
28 except:
29 python_version = (1,5)
30 if python_version < (2, 4):
31 sys.exit("Shinken require as a minimum Python 2.4.x, sorry")
32 elif python_version >= (3,):
33 sys.exit("Shinken is not yet compatible with Python3k, sorry")
35 from setuptools import setup, find_packages
36 from glob import glob
37 import os
38 import itertools
39 import ConfigParser
40 try:
41 import pwd
42 import grp
43 except ImportError:
44 # assume non-unix platform
45 pass
47 DEFAULT_OWNER = 'shinken'
48 DEFAULT_GROUP = 'shinken'
50 from distutils import log
51 from distutils.core import Command
52 from distutils.command.build import build as _build
53 from distutils.command.install import install as _install
54 from distutils.util import change_root
55 from distutils.errors import DistutilsOptionError
57 class build(_build):
58 sub_commands = _build.sub_commands + [
59 ('build_config', None),
61 user_options = _build.user_options + [
62 ('build-config', None, 'directory to build the config files to'),
64 def initialize_options(self):
65 _build.initialize_options(self)
66 self.build_config = None
68 def finalize_options (self):
69 _build.finalize_options(self)
70 if self.build_config is None:
71 self.build_config = os.path.join(self.build_base, 'etc')
73 class install(_install):
74 sub_commands = _install.sub_commands + [
75 ('install_config', None),
77 user_options = _install.user_options + [
78 ('etc-path=', None, 'read-only single-machine data'),
79 ('var-path=', None, 'modifiable single-machine data'),
80 ('plugins-path=', None, 'program executables'),
81 ('owner=', None, ('change owner for etc/* and var '
82 '(default: %s)' % DEFAULT_OWNER)),
83 ('group=', None, ('change group for etc/* and var '
84 '(default: %s)' % DEFAULT_GROUP)),
87 def initialize_options(self):
88 _install.initialize_options(self)
89 self.etc_path = None
90 self.var_path = None
91 self.plugins_path = None
92 self.owner = None
93 self.group = None
95 def finalize_options(self):
96 _install.finalize_options(self)
97 if self.etc_path is None:
98 self.etc_path = default_paths['etc']
99 if self.var_path is None:
100 self.var_path = default_paths['var']
101 if self.plugins_path is None:
102 self.plugins_path = default_paths['libexec']
103 if self.owner is None:
104 self.owner = DEFAULT_OWNER
105 if self.group is None:
106 self.group = DEFAULT_GROUP
108 if self.root:
109 for attr in ('etc_path', 'var_path', 'plugins_path'):
110 setattr(self, attr, change_root(self.root, getattr(self, attr)))
113 class build_config(Command):
114 description = "build the shinken config files"
116 user_options = [
117 ('build-dir=', None, "directory to build the config files to"),
120 def initialize_options (self):
121 self.build_dir = None
122 self.build_base = None
123 self.etc_path = None
124 self.var_path = None
125 self.plugins_path = None
127 self._install_scripts = None
129 def finalize_options (self):
130 self.set_undefined_options('build',
131 ('build_base', 'build_base'),
132 ('build_config', 'build_dir'),
134 self.set_undefined_options('install',
135 ('install_scripts', '_install_scripts'),
137 self.set_undefined_options('install_config',
138 ('etc_path', 'etc_path'),
139 ('var_path', 'var_path'),
140 ('plugins_path', 'plugins_path'),
142 if self.build_dir is None:
143 self.build_dir = os.path.join(self.build_base, 'etc')
146 def run(self):
147 if not self.dry_run:
148 self.mkpath(self.build_dir)
149 self.generate_default_shinken_file()
150 self.update_configfiles()
152 def generate_default_shinken_file(self):
153 # The default file must have good values for the directories:
154 # etc, var and where to push scripts that launch the app.
155 templatefile = "bin/default/shinken.in"
156 outfile = os.path.join(self.build_base, "bin/default/shinken")
158 log.info('generating %s from %s', outfile, templatefile)
159 if not self.dry_run:
160 self.mkpath(os.path.dirname(outfile))
161 # Read the template file
162 f = open(templatefile)
163 buf = f.read()
164 f.close
165 # substitute
166 buf = buf.replace("$ETC$", self.etc_path)
167 buf = buf.replace("$VAR$", self.var_path)
168 buf = buf.replace("$SCRIPTS_BIN$", self._install_scripts)
169 # write out the new file
170 f = open(outfile, "w")
171 f.write(buf)
172 f.close()
174 def update_configfiles(self):
175 # Here, even with --root we should change the file with good values
176 # then update the /etc/*d.ini files ../var value with the real var one
178 # Open a /etc/*d.ini file and change the ../var occurence with a
179 # good value from the configuration file
180 for name in daemon_ini_files:
181 inname = os.path.join('etc', name)
182 outname = os.path.join(self.build_dir, name)
183 log.info('updating path in %s', outname)
184 update_file_with_string(inname, outname,
185 "../var", self.var_path)
187 # And now the resource.cfg path with the value of libexec path
188 # Replace the libexec path by the one in the parameter file
189 for name in resource_cfg_files:
190 inname = os.path.join('etc', name)
191 outname = os.path.join(self.build_dir, name)
192 log.info('updating path in %s', outname)
193 update_file_with_string(inname, outname,
194 "/usr/local/shinken/libexec",
195 self.plugins_path)
197 # And update the nagios.cfg file for all /usr/local/shinken/var
198 # value with good one
199 for name in main_config_files:
200 inname = os.path.join('etc', name)
201 outname = os.path.join(self.build_dir, name)
202 log.info('updating path in %s', outname)
203 update_file_with_string(inname, outname,
204 "/usr/local/shinken/var",
205 self.var_path)
208 class install_config(Command):
209 description = "install the shinken config files"
211 user_options = [
212 ('install-dir=', 'd', "directory to install config files to"),
213 ('build-dir=','b', "build directory (where to install from)"),
214 ('force', 'f', "force installation (overwrite existing files)"),
215 ('skip-build', None, "skip the build steps"),
218 boolean_options = ['force', 'skip-build']
220 def initialize_options(self):
221 self.build_dir = None
222 self.force = None
223 self.skip_build = None
224 self.owner = None
225 self.group = None
227 self.root = None
228 self.etc_path = None # typically /etc on Posix systems
229 self.var_path = None # typically /var on Posix systems
230 self.plugins_path = None # typically /libexec on Posix systems
232 def finalize_options(self):
233 self.set_undefined_options('build',
234 ('build_config', 'build_dir'))
235 self.set_undefined_options('install',
236 ('root', 'root'),
237 ('etc_path', 'etc_path'),
238 ('var_path', 'var_path'),
239 ('plugins_path', 'plugins_path'),
240 ('owner', 'owner'),
241 ('group', 'group'))
243 def run(self):
244 #log.warn('>>> %s', self.lib)
245 log.warn('>>> %s', self.etc_path)
246 if not self.skip_build:
247 self.run_command('build_config')
248 self.outfiles = self.copy_tree(self.build_dir, self.etc_path)
251 if pwd:
252 # assume a posix system
253 uid = self.get_uid(self.owner)
254 gid = self.get_gid(self.group)
255 for file in self.get_outputs():
256 log.info("Changing owner of %s to %s:%s", file, self.owner, self.group)
257 if not self.dry_run:
258 os.chown(file, uid, gid)
259 # recursivly changing permissions for etc/shinken and var/lib/shinken
260 self.recursive_chown(self.etc_path, uid, gid, self.owner, self.group)
261 self.recursive_chown(self.var_path, uid, gid, self.owner, self.group)
264 def get_inputs (self):
265 return self.distribution.configs or []
267 def get_outputs(self):
268 return self.outfiles or []
270 def recursive_chown(self, path, uid, gid, owner, group):
271 log.info("Changing owner of %s to %s:%s", path, owner, group)
272 if not self.dry_run:
273 os.chown(path, uid, gid)
274 for dirname, dirs, files in os.walk(path):
275 for path in itertools.chain(dirs, files):
276 path = os.path.join(dirname, path)
277 os.chown(path, uid, gid)
279 @staticmethod
280 def get_uid(user_name):
281 try:
282 return pwd.getpwnam(user_name)[2]
283 except KeyError, exp:
284 raise DistutilsOptionError("The user %s is unknown. "
285 "Maybe you should create this user"
286 % user_name)
288 @staticmethod
289 def get_gid(group_name):
290 try:
291 return grp.getgrnam(group_name)[2]
292 except KeyError, exp:
293 raise DistutilsOptionError("The group %s is unknown. "
294 "Maybe you should create this group"
295 % group_name)
298 def update_file_with_string(infilename, outfilename, match, new_string):
299 f = open(infilename)
300 buf = f.read()
301 f.close()
302 buf = buf.replace(match, new_string)
303 f = open(outfilename, "w")
304 f.write(buf)
305 f.close()
308 # Set the default values for the paths
309 if os.name == 'nt':
310 default_paths = {'var': "c:\\shinken\\var",
311 'etc': "c:\\shinken\\etc",
312 'libexec': "c:\\shinken\\libexec",
314 else:
315 default_paths = {'var': "/var/lib/shinken/",
316 'etc': "/etc/shinken",
317 'libexec': "/usr/lib/shinken/plugins",
320 required_pkgs = []
321 if sys.version_info < (2, 5):
322 required_pkgs.append('pyro<4')
323 else:
324 required_pkgs.append('pyro')
325 if sys.version_info < (2, 6):
326 required_pkgs.append('multiprocessing')
328 etc_root = os.path.dirname(default_paths['etc'])
330 # nagios/shinken global config
331 main_config_files = ('nagios.cfg',
332 'nagios-windows.cfg',
333 'shinken-specific.cfg',
334 'shinken-specific-high-availability.cfg',
335 'shinken-specific-load-balanced-only.cfg',
338 # daemon configs
339 daemon_ini_files = ('brokerd.ini',
340 'brokerd-windows.ini',
341 'receiverd.ini',
342 'receiverd-windows.ini',
343 'pollerd.ini',
344 'pollerd-windows.ini',
345 'reactionnerd.ini',
346 'schedulerd.ini',
347 'schedulerd-windows.ini',
350 resource_cfg_files = ('resource.cfg', )
354 setup(
355 cmdclass = {'build': build,
356 'install': install,
357 'build_config': build_config,
358 'install_config': install_config},
359 name = "Shinken",
360 version = "0.5",
361 packages = find_packages(),
362 package_data = {'':['*.py','modules/*.py','modules/*/*.py']},
363 description = "Shinken is a monitoring tool compatible with Nagios configuration and plugins",
364 long_description=open('README').read(),
365 author = "Gabes Jean",
366 author_email = "naparuba@gmail.com",
367 license = "GNU Affero General Public License",
368 url = "http://www.shinken-monitoring.org",
369 zip_safe=False,
370 classifiers=['Development Status :: 5 - Production/Stable',
371 'Environment :: Console',
372 'Intended Audience :: System Administrators',
373 'License :: OSI Approved :: GNU Affero General Public License v3',
374 'Operating System :: MacOS :: MacOS X',
375 'Operating System :: Microsoft :: Windows',
376 'Operating System :: POSIX',
377 'Programming Language :: Python',
378 'Topic :: System :: Monitoring',
379 'Topic :: System :: Networking :: Monitoring',
382 install_requires = [
383 required_pkgs
386 scripts = glob('bin/shinken-[!_]*'),
387 data_files=[(default_paths['etc'],
388 [# other configs
389 'etc/commands.cfg',
390 'etc/contactgroups.cfg',
391 'etc/dependencies.cfg',
392 'etc/escalations.cfg',
393 'etc/hostgroups.cfg',
394 #'etc/resource.cfg', # see above
395 'etc/servicegroups.cfg',
396 'etc/templates.cfg',
397 'etc/timeperiods.cfg',
399 (os.path.join(default_paths['etc'], 'objects', 'hosts'),
400 glob('etc/objects/hosts/[!_]*.cfg')),
401 (os.path.join(default_paths['etc'], 'objects', 'services'),
402 glob('etc/objects/services/[!_]*.cfg')),
403 (os.path.join(default_paths['etc'], 'objects', 'contacts'),
404 glob('etc/objects/contacts/[!_]*.cfg')),
405 (os.path.join(default_paths['etc'], 'objects', 'discovery'), tuple() ),
406 (os.path.join(default_paths['etc'], 'certs') ,
407 glob('etc/certs/[!_]*.pem')),
408 (os.path.join('/etc', 'init.d'),
409 ['bin/init.d/shinken',
410 'bin/init.d/shinken-arbiter',
411 'bin/init.d/shinken-broker',
412 'bin/init.d/shinken-receiver',
413 'bin/init.d/shinken-poller',
414 'bin/init.d/shinken-reactionner',
415 'bin/init.d/shinken-scheduler']),
416 (os.path.join(etc_root, 'default',),
417 ['build/bin/default/shinken']),
418 (default_paths['var'], ['var/void_for_git']),
419 (default_paths['libexec'], ['libexec/check.sh']),