This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
wcsinst/wcsinst/wcsinstd/deploy.py

222 lines
8.2 KiB
Python

import string
import cPickle
import os
import zipfile
import subprocess
from urlparse import urlparse
from cStringIO import StringIO
import xml.etree.ElementTree as ET
from django.conf import settings
import psycopg2
from . import app_settings
def get_provider_key(provider_id):
return provider_id.replace('://', '-').replace('/', '-').replace('?', '-').replace(':', '-')
class DeployInstance(object):
skeleton = 'default'
skel_dir = None
collectivity_install_dir = None
def __init__(self, domain, title):
self.domain = domain
self.title = title
def make(self):
self.skel_dir = os.path.join(settings.MEDIA_ROOT, 'skeletons', self.skeleton)
url_template = app_settings.URL_TEMPLATE
self.url = str(url_template % {'domain': self.domain})
host, path = urlparse(self.url)[1:3]
if path.endswith('/'):
path = path[:-1]
coldir = host
if path:
coldir += path.replace('/', '+')
self.collectivity_install_dir = os.path.join(app_settings.WCS_APP_DIR, coldir)
if os.path.exists(self.collectivity_install_dir):
# site exists, let's update it
pass
anew = False
else:
anew = True
os.mkdir(self.collectivity_install_dir)
z = zipfile.ZipFile(os.path.join(self.skel_dir, 'export.wcs'), 'r')
for f in z.namelist():
path = os.path.join(self.collectivity_install_dir, f)
data = z.read(f)
if not os.path.exists(os.path.dirname(path)):
os.mkdir(os.path.dirname(path))
open(path, 'w').write(data)
z.close()
config_file = os.path.join(self.collectivity_install_dir, 'config.pck')
if os.path.exists(config_file):
wcs_cfg = cPickle.load(file(os.path.join(self.collectivity_install_dir, 'config.pck')))
else:
wcs_cfg = {}
has_sql = self.make_sql_config(wcs_cfg)
self.make_sso_config(wcs_cfg)
self.make_site_options()
cPickle.dump(wcs_cfg, file(config_file, 'w'))
if has_sql:
self.make_sql_tables(wcs_cfg)
self.make_apache_vhost()
self.reload_apache()
def make_sql_config(self, wcs_cfg):
if not wcs_cfg.get('postgresql'):
# this is not a site configured to use SQL
return False
database_name = wcs_cfg['postgresql'].get('database', 'wcs')
domain_table_name = self.domain.replace('-', '_').replace('.', '_')
if '_' in database_name:
database_name = '%s_%s' % (database_name.split('_')[0], domain_table_name)
else:
database_name = '%s_%s' % (database_name, domain_table_name)
postgresql_cfg = {}
for k, v in wcs_cfg['postgresql'].items():
if v:
postgresql_cfg[k] = v
try:
pgconn = psycopg2.connect(**postgresql_cfg)
except psycopg2.Error:
# XXX: log
raise
pgconn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
cur = pgconn.cursor()
try:
cur.execute('''CREATE DATABASE %s''' % database_name)
except psycopg2.Error as e:
print 'got psycopg2 error:', e
cur.close()
wcs_cfg['postgresql']['database'] = database_name
return True
def make_sql_tables(self, wcs_cfg):
params = []
for param in ('database', 'user', 'password', 'host', 'port'):
if wcs_cfg.get('postgresql').get(param):
if param == 'database':
params.append('--dbname')
else:
params.append('--' + param)
params.append(wcs_cfg.get('postgresql').get(param))
os.system('%s convert-to-sql %s %s' % (app_settings.WCSCTL_SCRIPT, ' '.join(params), self.domain))
def make_sso_config(self, wcs_cfg):
has_idff = False
has_saml2 = False
service_provider_configuration = {}
if self.url.endswith('/'):
url_stripped = self.url[:-1]
else:
url_stripped = self.url
if os.path.exists(os.path.join(self.skel_dir, 'idff-metadata-template')):
# there's a ID-FF metadata template, so we do the ID-FF stuff
has_idff = True
service_provider_configuration.update({
'base_url': '%s/liberty' % url_stripped,
'metadata': 'metadata.xml',
'providerid': '%s/liberty/metadata' % url_stripped,
})
idff_metadata_template = file(
os.path.join(self.skel_dir, 'idff-metadata-template')).read()
file(os.path.join(self.collectivity_install_dir, 'metadata.xml'), 'w').write(
string.Template(idff_metadata_template).substitute({'url': url_stripped}))
if os.path.exists(os.path.join(self.skel_dir, 'saml2-metadata-template')):
# there's a SAMLv2 metadata template, so we do the SAMLv2 stuff
has_saml2 = True
service_provider_configuration.update({
'saml2_base_url': '%s/saml' % url_stripped,
'saml2_metadata': 'saml2-metadata.xml',
'saml2_providerid': '%s/saml/metadata' % url_stripped
})
saml2_metadata_template = file(
os.path.join(self.skel_dir, 'saml2-metadata-template')).read()
file(os.path.join(self.collectivity_install_dir, 'saml2-metadata.xml'), 'w').write(
string.Template(saml2_metadata_template).substitute({'url': url_stripped}))
if has_idff or has_saml2:
idp_metadata = ET.parse(file(os.path.join(self.skel_dir, 'idp-metadata.xml')))
entity_id = idp_metadata.getroot().attrib['entityID']
idp_key = get_provider_key(entity_id)
wcs_cfg['identification'] = {'methods': ['idp']}
wcs_cfg['idp'] = {
idp_key: {
'metadata': 'provider-%s-metadata.xml' % idp_key,
'metadata_url': entity_id,
'publickey_url': None,
'role': 2}}
wcs_cfg['sp'] = {
'common_domain': None,
'common_domain_getter_url': None,
'organization_name': self.title.encode('utf-8'),
'privatekey': 'private-key.pem',
'publickey': 'public-key.pem'}
wcs_cfg['sp'].update(service_provider_configuration)
file(os.path.join(self.collectivity_install_dir, 'provider-%s-metadata.xml' % idp_key), 'w').write(
file(os.path.join(self.skel_dir, 'idp-metadata.xml')).read())
file(os.path.join(self.collectivity_install_dir, 'public-key.pem'), 'w').write(
file(os.path.join(self.skel_dir, 'public-key.pem')).read())
file(os.path.join(self.collectivity_install_dir, 'private-key.pem'), 'w').write(
file(os.path.join(self.skel_dir, 'private-key.pem')).read())
else:
wcs_cfg['identification'] = {'methods': ['password']}
def make_site_options(self):
options_template_path = os.path.join(self.skel_dir, 'site-options.cfg')
if not os.path.exists(options_template_path):
return
options_template = file(options_template_path).read()
file(os.path.join(self.collectivity_install_dir, 'site-options.cfg'), 'w').write(
string.Template(options_template).substitute({'domain': self.domain}))
def make_apache_vhost(self):
apache_vhost_template_path = os.path.join(self.skel_dir, 'apache-vhost.conf')
if not os.path.exists(apache_vhost_template_path):
return
apache_vhost_template = file(apache_vhost_template_path).read()
apache_dir = os.path.join(settings.MEDIA_ROOT, 'vhosts.d')
if not os.path.exists(apache_dir):
os.mkdir(apache_dir)
file(os.path.join(apache_dir, '%s.conf' % self.domain), 'w').write(
string.Template(apache_vhost_template).substitute({'domain': self.domain}))
def reload_apache(self):
os.system('sudo -n /etc/init.d/apache2 reload')