153 lines
5.9 KiB
Python
153 lines
5.9 KiB
Python
# bijoe - BI dashboard
|
|
# Copyright (C) 2015 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import hashlib
|
|
import os
|
|
|
|
from django.utils.six.moves import configparser as ConfigParser
|
|
from django.utils.six.moves.urllib import parse as urlparse
|
|
|
|
try:
|
|
import sentry_sdk
|
|
except ImportError:
|
|
sentry_sdk = None
|
|
|
|
from django.conf import settings
|
|
from django.utils.encoding import force_str
|
|
from hobo.agent.common.management.commands import hobo_deploy
|
|
from hobo.multitenant.settings_loaders import KnownServices
|
|
from tenant_schemas.utils import tenant_context
|
|
|
|
|
|
def pg_dsn_quote(value):
|
|
return "'%s'" % str(value).replace('\\', '\\\\').replace('\'', '\\\'')
|
|
|
|
|
|
def config_parser_quote(value):
|
|
return value.replace('%', '%%')
|
|
|
|
|
|
def truncate_pg_identifier(identifier, hash_length=6, force_hash=False):
|
|
if len(identifier) < 64 and not force_hash:
|
|
return identifier
|
|
else:
|
|
# insert hash in the middle, to keep some readability
|
|
return (
|
|
identifier[: (63 - hash_length) // 2]
|
|
+ hashlib.md5(identifier.encode('utf-8')).hexdigest()[:hash_length]
|
|
+ identifier[-(63 - hash_length) // 2 :]
|
|
)
|
|
|
|
|
|
def schema_from_url(url, hash_length=6):
|
|
netloc = urlparse.urlparse(url).netloc
|
|
assert netloc
|
|
domain = netloc.split(':')[0]
|
|
pg_identifier = domain.replace('.', '_').replace('-', '_')
|
|
return truncate_pg_identifier(pg_identifier, hash_length=hash_length)
|
|
|
|
|
|
class Command(hobo_deploy.Command):
|
|
def deploy_specifics(self, hobo_environment, tenant):
|
|
super().deploy_specifics(hobo_environment, tenant)
|
|
with tenant_context(tenant):
|
|
services = hobo_environment.get('services')
|
|
ini_file = os.path.join(tenant.get_directory(), 'wcs-olap.ini')
|
|
schemas_path = os.path.join(tenant.get_directory(), 'schemas')
|
|
config = ConfigParser.SafeConfigParser()
|
|
config.read(ini_file)
|
|
|
|
self.configure_sentry(config)
|
|
if not os.path.exists(schemas_path):
|
|
os.mkdir(schemas_path)
|
|
if not config.has_section('wcs-olap'):
|
|
config.add_section('wcs-olap')
|
|
config.set('wcs-olap', 'cubes_model_dirs', schemas_path)
|
|
pg_dsn_parts = []
|
|
for pg_dsn_part in [
|
|
('NAME', 'dbname'),
|
|
('HOST', 'host'),
|
|
('USER', 'user'),
|
|
('PASSWORD', 'password'),
|
|
('PORT', 'port'),
|
|
]:
|
|
if settings.DATABASES['default'].get(pg_dsn_part[0]):
|
|
pg_dsn_parts.append(
|
|
'%s=%s'
|
|
% (pg_dsn_part[1], pg_dsn_quote(settings.DATABASES['default'].get(pg_dsn_part[0])))
|
|
)
|
|
config.set('wcs-olap', 'pg_dsn', config_parser_quote(' '.join(pg_dsn_parts)))
|
|
|
|
for service in services:
|
|
if service.get('this'):
|
|
this = service
|
|
break
|
|
else:
|
|
raise RuntimeError('unable to find this service')
|
|
our_key = this['secret_key']
|
|
for service in services:
|
|
base_url = service.get('base_url')
|
|
if (
|
|
service.get('this')
|
|
or not service.get('secret_key')
|
|
or service['service-id'] != 'wcs'
|
|
or not service.get('base_url')
|
|
):
|
|
continue
|
|
elif service.get('secondary') and not config.has_section(base_url):
|
|
# skip secondary instances unless they were already added,
|
|
# in that case they need to be kept uptodate
|
|
continue
|
|
schema = schema_from_url(base_url)
|
|
orig = urlparse.urlparse(this.get('base_url')).netloc.split(':')[0]
|
|
their_key = service.get('secret_key')
|
|
key = KnownServices.shared_secret(our_key, their_key)
|
|
|
|
if config.has_section(base_url):
|
|
config.remove_section(base_url)
|
|
config.add_section(base_url)
|
|
config.set(base_url, 'orig', orig)
|
|
config.set(base_url, 'key', key)
|
|
config.set(base_url, 'schema', schema)
|
|
config.set(base_url, 'cubes_label', force_str(service.get('title')))
|
|
if 'slug' in service:
|
|
config.set(base_url, 'cubes_slug', service['slug'])
|
|
with open(ini_file, 'w') as f:
|
|
config.write(f)
|
|
|
|
def has_sentry(self):
|
|
if not sentry_sdk:
|
|
return False
|
|
if not sentry_sdk.Hub.current or not sentry_sdk.Hub.current.client:
|
|
# not configured
|
|
return False
|
|
client = sentry_sdk.Hub.current.client
|
|
if not client.dsn:
|
|
# not configured
|
|
return False
|
|
return True
|
|
|
|
def configure_sentry(self, config):
|
|
if self.has_sentry():
|
|
if not config.has_section('sentry'):
|
|
config.add_section('sentry')
|
|
config.set('sentry', 'dsn', sentry_sdk.Hub.current.client.dsn)
|
|
if sentry_sdk.Hub.current.client.options.get('environment'):
|
|
config.set('sentry', 'environment', sentry_sdk.Hub.current.client.options['environment'])
|
|
else:
|
|
if config.has_section('sentry'):
|
|
config.remove_section('sentry')
|