*Be less strict with pylint checks to make the jenkins test happy
[shinken.git] / setup.py
blobedb6216e8c2673907df9f7b033d0b4cd4ce84a65
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/>.
23 from setuptools import setup, find_packages
24 from glob import glob
25 import os, sys
26 import ConfigParser
27 try:
28 import pwd
29 import grp
30 except ImportError:
31 # assume non-unix platform
32 pass
34 # Shinken requires Python 2.4, but does not support Python 3.x yet.
35 try:
36 python_version = sys.version_info
37 except:
38 python_version = (1,5)
41 ## Make sure people are using Python 2.4 or higher
42 if python_version < (2, 4):
43 sys.exit("Shinken require as a minimum Python 2.4.x, sorry")
44 elif python_version >= (3,):
45 sys.exit("Shinken is not yet compatible with Python3k, sorry")
48 from distutils import log
49 from distutils.core import Command
50 from distutils.command.build import build as _build
51 from distutils.command.install import install as _install
52 from distutils.util import change_root
53 from distutils.errors import DistutilsOptionError
55 class build(_build):
56 sub_commands = _build.sub_commands + [
57 ('build_config', None),
59 user_options = _build.user_options + [
60 ('build-config', None, 'directory to build the configfiles to'),
62 def initialize_options(self):
63 _build.initialize_options(self)
64 self.build_config = None
66 def finalize_options (self):
67 _build.finalize_options(self)
68 if self.build_config is None:
69 self.build_config = os.path.join(self.build_base, 'etc')
71 class install(_install):
72 sub_commands = _install.sub_commands + [
73 ('install_config', None),
75 user_options = _install.user_options + [
76 ('etc-path=', None, 'read-only single-machine data'),
77 ('var-path=', None, 'modifiable single-machine data'),
78 ('plugins-path=', None, 'program executables'),
81 def initialize_options(self):
82 _install.initialize_options(self)
83 self.etc_path = None
84 self.var_path = None
85 self.var_owner = None
86 self.var_group = None
87 self.plugins_path = None
89 def finalize_options(self):
90 _install.finalize_options(self)
91 if self.etc_path is None:
92 self.etc_path = paths_and_owners['etc']['path']
93 if self.var_path is None:
94 self.var_path = paths_and_owners['var']['path']
95 self.var_owner = paths_and_owners['var']['owner']
96 self.var_group = paths_and_owners['var']['group']
97 if self.plugins_path is None:
98 self.plugins_path = paths_and_owners['libexec']['path']
99 if self.root:
100 for attr in ('etc_path', 'var_path', 'plugins_path'):
101 setattr(self, attr, change_root(self.root, getattr(self, attr)))
104 class build_config(Command):
105 description = "build the shinken config files"
107 user_options = [
108 ('build-dir=', None, "directory to build the configfiles to"),
111 def initialize_options (self):
112 self.build_dir = None
113 self.build_base = None
114 self.etc_path = None
115 self.var_path = None
116 self.plugins_path = None
118 self._install_scripts = None
120 def finalize_options (self):
121 self.set_undefined_options('build',
122 ('build_base', 'build_base'),
123 ('build_config', 'build_dir'),
125 self.set_undefined_options('install',
126 ('install_scripts', '_install_scripts'),
128 self.set_undefined_options('install_config',
129 ('etc_path', 'etc_path'),
130 ('var_path', 'var_path'),
131 ('plugins_path', 'plugins_path'),
133 if self.build_dir is None:
134 self.build_dir = os.path.join(self.build_base, 'etc')
137 def run(self):
138 if not self.dry_run:
139 self.mkpath(self.build_dir)
140 self.generate_default_shinken_file()
141 self.update_configfiles()
143 def generate_default_shinken_file(self):
144 # The default file must have good values for the directories:
145 # etc, var and where to push scripts that launch the app.
146 templatefile = "bin/default/shinken.in"
147 outfile = os.path.join(self.build_base, "bin/default/shinken")
149 log.info('generating %s from %s', outfile, templatefile)
150 if not self.dry_run:
151 self.mkpath(os.path.dirname(outfile))
152 # Read the template file
153 f = open(templatefile)
154 buf = f.read()
155 f.close
156 # substitute
157 buf = buf.replace("$ETC$", self.etc_path)
158 buf = buf.replace("$VAR$", self.var_path)
159 buf = buf.replace("$SCRIPTS_BIN$", self._install_scripts)
160 # write out the new file
161 f = open(outfile, "w")
162 f.write(buf)
163 f.close()
165 def update_configfiles(self):
166 # Here, even with --root we should change the file with good values
167 # then update the /etc/*d.ini files ../var value with the real var one
169 # Open a /etc/*d.ini file and change the ../var occurence with a
170 # good value from the configuration file
171 for name in ('brokerd.ini',
172 'schedulerd.ini',
173 'pollerd.ini',
174 'reactionnerd.ini'):
175 inname = os.path.join('etc', name)
176 outname = os.path.join(self.build_dir, name)
177 log.info('updating path in %s', outname)
178 update_file_with_string(inname, outname,
179 "../var", self.var_path)
181 # And now the resource.cfg path with the value of libexec path
182 # Replace the libexec path by the one in the parameter file
183 for name in ('resource.cfg', ):
184 inname = os.path.join('etc', name)
185 outname = os.path.join(self.build_dir, name)
186 log.info('updating path in %s', outname)
187 update_file_with_string(inname, outname,
188 "/usr/local/shinken/libexec",
189 self.plugins_path)
191 # And update the nagios.cfg file for all /usr/local/shinken/var
192 # value with good one
193 for name in ('nagios.cfg',
194 'shinken-specific.cfg',
195 'shinken-specific-high-availability.cfg',
196 'shinken-specific-load-balanced-only.cfg',
198 inname = os.path.join('etc', name)
199 outname = os.path.join(self.build_dir, name)
200 log.info('updating path in %s', outname)
201 update_file_with_string(inname, outname,
202 "/usr/local/shinken/var",
203 self.var_path)
206 class install_config(Command):
207 description = "install the shinken config files"
209 user_options = [
210 ('install-dir=', 'd', "directory to install config files to"),
211 ('build-dir=','b', "build directory (where to install from)"),
212 ('force', 'f', "force installation (overwrite existing files)"),
213 ('skip-build', None, "skip the build steps"),
216 boolean_options = ['force', 'skip-build']
218 def initialize_options(self):
219 self.build_dir = None
220 self.force = None
221 self.skip_build = None
222 self.owner = None
223 self.group = None
225 self.root = None
226 self.etc_path = None # typically /etc on Posix systems
227 self.var_path = None # typically /var on Posix systems
228 self.var_owner = None # typically shinken
229 self.var_group = None # typically shinken too
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 ('var_owner', 'var_owner'),
240 ('var_group', 'var_group'),
241 ('plugins_path', 'plugins_path'))
242 if self.owner is None and pwd:
243 self.owner = pwd.getpwuid(os.getuid())[0]
244 if self.group is None and grp:
245 self.group = grp.getgrgid(os.getgid())[0]
248 def run(self):
249 #log.warn('>>> %s', self.lib)
250 log.warn('>>> %s', self.etc_path)
251 if not self.skip_build:
252 self.run_command('build_config')
253 self.outfiles = self.copy_tree(self.build_dir, self.etc_path)
256 if pwd:
257 # assume a posix system
258 uid = self.get_uid(self.owner)
259 gid = self.get_gid(self.group)
260 for file in self.get_outputs():
261 log.info("Changing owner of %s to %s:%s", file, self.owner, self.group)
262 if not self.dry_run:
263 os.chown(file, uid, gid)
264 # And set the /var/lib/shinken in correct owner too
265 # TODO : (j gabes) I can't access to self.var_owner (None) and
266 # I don't know how to change it o I use the global variables
267 var_uid = self.get_uid(var_owner)
268 var_gid = self.get_uid(var_group)
269 if not self.dry_run:
270 os.chown(self.var_path, var_uid, var_gid)
273 def get_inputs (self):
274 return self.distribution.configs or []
276 def get_outputs(self):
277 return self.outfiles or []
279 @staticmethod
280 def _chown(path, owner, group):
281 log.info("Changing owner of %s to %s:%s", path, owner, group)
282 if not self.dry_run:
283 os.chown(path, uid, gid)
284 for root, dirs, files in os.walk(path):
285 for path in itertools.chain(dirs, files):
286 path = os.path.join(root, path)
288 @staticmethod
289 def get_uid(user_name):
290 try:
291 return pwd.getpwnam(user_name)[2]
292 except KeyError, exp:
293 raise DistutilsOptionError("The user %s is unknown. "
294 "Maybe you should create this user"
295 % user_name)
297 @staticmethod
298 def get_gid(group_name):
299 try:
300 return grp.getgrnam(group_name)[2]
301 except KeyError, exp:
302 raise DistutilsOptionError("The group %s is unknown. "
303 "Maybe you should create this group"
304 % group_name)
307 def update_file_with_string(infilename, outfilename, match, new_string):
308 f = open(infilename)
309 buf = f.read()
310 f.close()
311 buf = buf.replace(match, new_string)
312 f = open(outfilename, "w")
313 f.write(buf)
314 f.close()
317 #Set the default values for the paths
318 #owners and groups
319 if os.name == 'nt':
320 paths_and_owners = {'var':{'path': "c:\\shinken\\var",
321 'owner': None,
322 'group': None },
323 'etc': {'path': "c:\\shinken\\etc",
324 'owner': None,
325 'group': None},
326 'libexec': {'path': "c:\\shinken\\libexec",
327 'owner': None,
328 'group': None},
330 else:
331 paths_and_owners = {'var': {'path': "/var/lib/shinken/",
332 'owner' : 'shinken',
333 'group' : 'shinken' },
334 'etc': {'path': "/etc/shinken",
335 'owner': 'shinken',
336 'group': 'shinken'},
337 'libexec': {'path': "/usr/lib/shinken/plugins",
338 'owner': 'shinken',
339 'group': 'shinken'},
342 required_pkgs = []
343 if sys.version_info < (2, 5):
344 required_pkgs.append('pyro<4')
345 else:
346 required_pkgs.append('pyro')
347 if sys.version_info < (2, 6):
348 required_pkgs.append('multiprocessing')
350 etc_path = paths_and_owners['etc']['path']
351 etc_root = os.path.dirname(etc_path)
352 libexec_path = paths_and_owners['libexec']['path']
353 var_path = paths_and_owners['var']['path']
354 var_owner = paths_and_owners['var']['owner']
355 var_group = paths_and_owners['var']['group']
357 setup(
358 cmdclass = {'build': build,
359 'install': install,
360 'build_config': build_config,
361 'install_config': install_config},
362 name = "Shinken",
363 version = "0.5",
364 packages = find_packages(),
365 package_data = {'':['*.py','modules/*.py','modules/*/*.py']},
366 description = "Shinken is a monitoring tool compatible with Nagios configuration and plugins",
367 long_description=open('README').read(),
368 author = "Gabes Jean",
369 author_email = "naparuba@gmail.com",
370 license = "GNU Affero General Public License",
371 url = "http://www.shinken-monitoring.org",
372 zip_safe=False,
373 classifiers=['Development Status :: 5 - Production/Stable',
374 'Environment :: Console',
375 'Intended Audience :: System Administrators',
376 'License :: OSI Approved :: GNU Affero General Public License v3',
377 'Operating System :: MacOS :: MacOS X',
378 'Operating System :: Microsoft :: Windows',
379 'Operating System :: POSIX',
380 'Programming Language :: Python',
381 'Topic :: System :: Monitoring',
382 'Topic :: System :: Networking :: Monitoring',
385 install_requires = [
386 required_pkgs
389 scripts = glob('bin/shinken-[!_]*'),
390 data_files=[(etc_path,
391 [# nagios/shinken global config
392 #"etc/nagios.cfg",
393 'etc/nagios-windows.cfg',
394 #'etc/shinken-specific.cfg',
395 #'etc/shinken-specific-high-availability.cfg',
396 #'etc/shinken-specific-load-balanced-only.cfg',
398 # daemon configs
399 #'etc/brokerd.ini',
400 'etc/brokerd-windows.ini',
401 #'etc/pollerd.ini',
402 'etc/pollerd-windows.ini',
403 #'etc/reactionnerd.ini',
404 #'etc/schedulerd.ini',
405 'etc/schedulerd-windows.ini',
407 # other configs
408 'etc/commands.cfg',
409 'etc/contactgroups.cfg',
410 'etc/dependencies.cfg',
411 'etc/escalations.cfg',
412 'etc/hostgroups.cfg',
413 'etc/resource.cfg',
414 'etc/servicegroups.cfg',
415 'etc/templates.cfg',
416 'etc/timeperiods.cfg',
418 (os.path.join(etc_path, 'objects', 'hosts'),
419 glob('etc/objects/hosts/[!_]*.cfg')),
420 (os.path.join(etc_path, 'objects', 'services'),
421 glob('etc/objects/services/[!_]*.cfg')),
422 (os.path.join(etc_path, 'objects', 'contacts'),
423 glob('etc/objects/contacts/[!_]*.cfg')),
424 (os.path.join(etc_path, 'certs') ,
425 glob('etc/certs/[!_]*.pem')),
426 (os.path.join('/etc', 'init.d'),
427 ['bin/init.d/shinken',
428 'bin/init.d/shinken-arbiter',
429 'bin/init.d/shinken-broker',
430 'bin/init.d/shinken-poller',
431 'bin/init.d/shinken-reactionner',
432 'bin/init.d/shinken-scheduler']),
433 (os.path.join(etc_root, 'default',),
434 ['bin/default/shinken']),
435 (var_path, ['var/void_for_git']),
436 (libexec_path, ['libexec/check.sh']),
441 # We will chown shinken:shinken for all /etc/shinken
442 # and /var/lib/shinken.
445 #if os.name != 'nt' and ('install' in sys.argv or 'sdist' in sys.argv):
446 # for dir in ['etc', 'var']:
447 # _chown(paths_and_owners[dir]['path'],
448 # paths_and_owners[dir]['owner'],
449 # paths_and_owners[dir]['owner'])