Add Krb configuration code
[cascardo/ipsilon.git] / ipsilon / install / server.py
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2014  Simo Sorce <simo@redhat.com>
4 #
5 # see file 'COPYING' for use and warranty information
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 from ipsilon.login.common import LoginMgrsInstall
21 from ipsilon.providers.common import ProvidersInstall
22 import argparse
23 import cherrypy
24 import logging
25 import os
26 import pwd
27 import shutil
28 import socket
29 import sys
30 import time
31
32
33 TEMPLATES = '/usr/share/ipsilon/templates/install'
34 CONFDIR = '/etc/ipsilon'
35 HTTPDCONFD = '/etc/httpd/conf.d'
36
37
38 class ConfigurationError(Exception):
39
40     def __init__(self, message):
41         super(ConfigurationError, self).__init__(message)
42         self.message = message
43
44     def __str__(self):
45         return repr(self.message)
46
47
48 #Silence cherrypy logging to screen
49 cherrypy.log.screen = False
50
51 # Regular logging
52 LOGFILE = '/var/log/ipsilon-install.log'
53 logger = logging.getLogger()
54
55
56 def openlogs():
57     global logger  # pylint: disable=W0603
58     if os.path.isfile(LOGFILE):
59         try:
60             created = '%s' % time.ctime(os.path.getctime(LOGFILE))
61             shutil.move(LOGFILE, '%s.%s' % (LOGFILE, created))
62         except IOError:
63             pass
64     logger = logging.getLogger()
65     try:
66         lh = logging.FileHandler(LOGFILE)
67     except IOError, e:
68         print >> sys.stderr, 'Unable to open %s (%s)' % (LOGFILE, str(e))
69         lh = logging.StreamHandler(sys.stderr)
70     formatter = logging.Formatter('[%(asctime)s] %(message)s')
71     lh.setFormatter(formatter)
72     logger.addHandler(lh)
73
74
75 def install(plugins, args):
76     logger.info('Installation initiated')
77     now = time.strftime("%Y%m%d%H%M%S", time.gmtime())
78
79     logger.info('Installing default config files')
80     ipsilon_conf = os.path.join(CONFDIR, 'ipsilon.conf')
81     idp_conf = os.path.join(CONFDIR, 'idp.conf')
82     args['httpd_conf'] = os.path.join(HTTPDCONFD, 'idp.conf')
83     if os.path.exists(ipsilon_conf):
84         shutil.move(ipsilon_conf, '%s.bakcup.%s' % (ipsilon_conf, now))
85     if os.path.exists(idp_conf):
86         shutil.move(idp_conf, '%s.backup.%s' % (idp_conf, now))
87     shutil.copy(os.path.join(TEMPLATES, 'ipsilon.conf'), CONFDIR)
88     shutil.copy(os.path.join(TEMPLATES, 'idp.conf'), CONFDIR)
89     if not os.path.exists(args['httpd_conf']):
90         os.symlink(idp_conf, args['httpd_conf'])
91     # Load the cherrypy config from the newly installed file so
92     # that db paths and all is properly set before configuring
93     # components
94     cherrypy.config.update(ipsilon_conf)
95
96     # Move pre-existing admin db away
97     admin_db = cherrypy.config['admin.config.db']
98     if os.path.exists(admin_db):
99         shutil.move(admin_db, '%s.backup.%s' % (admin_db, now))
100
101     logger.info('Configuring login managers')
102     for plugin_name in args['lm_order']:
103         plugin = plugins['Login Managers'][plugin_name]
104         plugin.configure(args)
105
106     logger.info('Configuring Authentication Providers')
107     for plugin_name in plugins['Auth Providers']:
108         plugin = plugins['Auth Providers'][plugin_name]
109         plugin.configure(args)
110
111
112 def uninstall(plugins, args):
113     logger.info('Uninstallation initiated')
114     raise Exception('Not Implemented')
115
116
117 def find_plugins():
118     plugins = {
119         'Login Managers': LoginMgrsInstall().plugins,
120         'Auth Providers': ProvidersInstall().plugins
121     }
122     return plugins
123
124
125 def parse_args(plugins):
126     parser = argparse.ArgumentParser(description='Ipsilon Install Options')
127     parser.add_argument('--version',
128                         action='version', version='%(prog)s 0.1')
129     parser.add_argument('-o', '--login-managers-order', dest='lm_order',
130                         help='Comma separated list of login managers')
131     parser.add_argument('--hostname',
132                         help="Machine's fully qualified host name")
133     parser.add_argument('--system-user', default='ipsilon',
134                         help="User account used to run the server")
135     parser.add_argument('--ipa', choices=['yes', 'no'], default='yes',
136                         help='Detect and use an IPA server for authentication')
137     parser.add_argument('--uninstall', action='store_true',
138                         help="Uninstall the server and all data")
139
140     lms = []
141
142     for plugin_group in plugins:
143         group = parser.add_argument_group(plugin_group)
144         for plugin_name in plugins[plugin_group]:
145             plugin = plugins[plugin_group][plugin_name]
146             if plugin.ptype == 'login':
147                 lms.append(plugin.name)
148             plugin.install_args(group)
149
150     args = vars(parser.parse_args())
151
152     if not args['hostname']:
153         args['hostname'] = socket.getfqdn()
154
155     if len(args['hostname'].split('.')) < 2:
156         raise ConfigurationError('Hostname: %s is not a FQDN')
157
158     try:
159         pwd.getpwnam(args['system_user'])
160     except KeyError:
161         raise ConfigurationError('User: %s not found on the system')
162
163     if args['lm_order'] is None:
164         args['lm_order'] = []
165         for name in lms:
166             if args[name] == 'yes':
167                 args['lm_order'].append(name)
168     else:
169         args['lm_order'] = args['lm_order'].split(',')
170
171     if len(args['lm_order']) == 0:
172         #force the basic pam provider if nothing else is selected
173         if 'pam' not in args:
174             parser.print_help()
175             sys.exit(-1)
176         args['lm_order'] = ['pam']
177         args['pam'] = 'yes'
178
179     return args
180
181 if __name__ == '__main__':
182     opts = []
183     out = 0
184     openlogs()
185     try:
186         fplugins = find_plugins()
187         opts = parse_args(fplugins)
188
189         logger.setLevel(logging.DEBUG)
190
191         logger.info('Intallation arguments:')
192         for k in sorted(opts.iterkeys()):
193             logger.info('%s: %s', k, opts[k])
194
195         if 'uninstall' in opts and opts['uninstall'] is True:
196             uninstall(fplugins, opts)
197
198         install(fplugins, opts)
199     except Exception, e:  # pylint: disable=broad-except
200         logger.exception(e)
201         if 'uninstall' in opts and opts['uninstall'] is True:
202             print 'Uninstallation aborted.'
203         else:
204             print 'Installation aborted.'
205         print 'See log file %s for details' % LOGFILE
206         out = 1
207     finally:
208         if out == 0:
209             if 'uninstall' in opts and opts['uninstall'] is True:
210                 print 'Uninstallation complete.'
211             else:
212                 print 'Installation complete.'
213     sys.exit(out)