Ottomata has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/392978 )

Change subject: Puppetization for superset
......................................................................


Puppetization for superset

This just sets up the superset service.
TODO: LVS, DNS, LDAP auth, etc.

Bug: T166689
Change-Id: Ib63b35e409ba4c8fbc77f342220f1f4c4f6fecea
---
M hieradata/labs/deployment-prep/common.yaml
M hieradata/role/common/deployment_server.yaml
M hieradata/role/common/statistics/web.yaml
A modules/profile/manifests/superset.pp
M modules/role/manifests/statistics/web.pp
A modules/superset/files/superset.profile.firejail
A modules/superset/manifests/init.pp
A modules/superset/templates/gunicorn_config.py.erb
A modules/superset/templates/initscripts/superset.systemd.erb
A modules/superset/templates/superset_config.py.erb
10 files changed, 313 insertions(+), 0 deletions(-)

Approvals:
  Ottomata: Looks good to me, approved
  Elukey: Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git a/hieradata/labs/deployment-prep/common.yaml 
b/hieradata/labs/deployment-prep/common.yaml
index 9930669..f0f3209 100644
--- a/hieradata/labs/deployment-prep/common.yaml
+++ b/hieradata/labs/deployment-prep/common.yaml
@@ -311,6 +311,10 @@
   eventstreams/deploy:
     repository: mediawiki/services/eventstreams/deploy
 
+  # Superset
+  analytics/superset/deploy:
+    repository: analytics/superset/deploy
+
   # IEG grant review
   iegreview/iegreview:
     repository: iegreview
diff --git a/hieradata/role/common/deployment_server.yaml 
b/hieradata/role/common/deployment_server.yaml
index 5c5e154..490d237 100644
--- a/hieradata/role/common/deployment_server.yaml
+++ b/hieradata/role/common/deployment_server.yaml
@@ -107,6 +107,9 @@
   # Public EventStreams service
   eventstreams/deploy:
     repository: mediawiki/services/eventstreams/deploy
+  # Superset
+  analytics/superset/deploy:
+    repository: analytics/superset/deploy
   gerrit/gerrit:
     repository: operations/software/gerrit
   graphoid/deploy: {}
diff --git a/hieradata/role/common/statistics/web.yaml 
b/hieradata/role/common/statistics/web.yaml
index f54e5f2..2a48bc2 100644
--- a/hieradata/role/common/statistics/web.yaml
+++ b/hieradata/role/common/statistics/web.yaml
@@ -4,3 +4,7 @@
   - statistics-web-users
   - statistics-admins
 profile::statistics::web::geowiki_host: 'stat1006.eqiad.wmnet'
+
+# Database password will be filled added in profile::superset from the
+# profile::superset::database_password hiera variable stored in the private 
repo.
+profile::superset::database_uri: 
mysql://[email protected]/superset
diff --git a/modules/profile/manifests/superset.pp 
b/modules/profile/manifests/superset.pp
new file mode 100644
index 0000000..7115dad
--- /dev/null
+++ b/modules/profile/manifests/superset.pp
@@ -0,0 +1,61 @@
+# == Class profile::superset
+# Sets up superset site.
+#
+# == Parameters
+#
+# [*database_uri*]
+#   SQL Alchemy database URI to use as the superset state store.
+#   This can be a passwordless URI if $database_password is provided.
+#
+# [*database_password*]
+#   If given, it will be inserted into the $database_uri.  This expects that 
$database_uri
+#   is of the form 'protocol://username@hostname/databasename'.
+#
+# [*admin_user*]
+#   Web UI admin user
+#
+# [*admin_password*]
+#   Web UI admin user password
+
+# [*secret_key*]
+#   flask secret key
+#
+# [*password_mapping*]
+#   Hash of sqlalchemy URIs to passwords.  This will be used
+#   for the SQLALCHEMY_CUSTOM_PASSWORD_STORE, to allow for
+#   passwords to external databases to be provided via configuration,
+#   rather than the web UI.
+#
+# [*statsd*]
+#   statsd host:port
+#
+class profile::superset(
+    $database_uri      = hiera('profile::superset::database_uri', 
'sqlite:////var/lib/superset/superset.db'),
+    $database_password = hiera('profile::superset::database_password', undef),
+    $admin_user        = hiera('profile::superset::admin_user', 'admin'),
+    $admin_password    = hiera('profile::superset::admin_pass', 'admin'),
+    $secret_key        = hiera('profile::superset::secret_key', 
'not_really_a_secret_key'),
+    $password_mapping  = hiera('profile::superset::password_mapping', undef),
+    $statsd            = hiera('statsd', undef),
+) {
+    # If given $database_password, insert it into $database_uri.
+    $full_database_uri = $database_password ? {
+        undef   => $database_uri,
+        default => regsubst($database_uri, '(\w+)://(\w*)@(.*)', 
"\\1://\\2:${database_password}@\\3")
+    }
+
+    class { '::superset':
+        database_uri     => $full_database_uri,
+        secret_key       => $secret_key,
+        admin_user       => $admin_user,
+        admin_password   => $admin_password,
+        password_mapping => $password_mapping,
+        statsd           => $statsd,
+    }
+
+    monitoring::service { 'superset':
+        description   => 'superset',
+        check_command => "check_tcp!${::superset::port}",
+        require       => Systemd::Service['superset'],
+    }
+}
diff --git a/modules/role/manifests/statistics/web.pp 
b/modules/role/manifests/statistics/web.pp
index 839fa77..dda3959 100644
--- a/modules/role/manifests/statistics/web.pp
+++ b/modules/role/manifests/statistics/web.pp
@@ -5,4 +5,7 @@
     }
 
     include ::profile::statistics::web
+
+    # Superset. T166689
+    include ::profile::superset
 }
diff --git a/modules/superset/files/superset.profile.firejail 
b/modules/superset/files/superset.profile.firejail
new file mode 100644
index 0000000..acd4e84
--- /dev/null
+++ b/modules/superset/files/superset.profile.firejail
@@ -0,0 +1,26 @@
+# system directories
+blacklist /sbin
+blacklist /usr/sbin
+blacklist /usr/local/sbin
+
+# system management
+blacklist ${PATH}/umount
+blacklist ${PATH}/mount
+blacklist ${PATH}/fusermount
+blacklist ${PATH}/su
+blacklist ${PATH}/sudo
+blacklist ${PATH}/xinput
+blacklist ${PATH}/evtest
+blacklist ${PATH}/xev
+blacklist ${PATH}/strace
+blacklist ${PATH}/nc
+blacklist ${PATH}/ncat
+
+blacklist /etc/shadow
+blacklist /etc/ssh
+blacklist /root
+blacklist /home
+noroot
+caps.drop all
+seccomp
+private-dev
diff --git a/modules/superset/manifests/init.pp 
b/modules/superset/manifests/init.pp
new file mode 100644
index 0000000..2041a3e
--- /dev/null
+++ b/modules/superset/manifests/init.pp
@@ -0,0 +1,141 @@
+# == Class superset
+# Installs superset via scap and runs it.
+#
+# If you are providing a custom $database_uri, you must ensure that the 
database exists
+# and the configured db user/pass in the URI can write to that database.
+# Tables will be auto created.
+#
+# == Parameters
+#
+# [*port*]
+#   Port on which superset will listen for HTTP connections.
+#
+# [*database_uri*]
+#   SQL Alchemy database URI.
+#
+# [*workers*]
+#   Number of gevent workers
+#
+# [*admin_user*]
+#   Web UI admin user
+#
+# [*admin_password*]
+#   Web UI admin user password
+#
+# [*secret_key*]
+#   flask secret key
+#
+# [*password_mapping*]
+#   Hash of sqlalchemy URIs to passwords.  This will be used
+#   for the SQLALCHEMY_CUSTOM_PASSWORD_STORE, to allow for
+#   passwords to external databases to be provided via configuration,
+#   rather than the web UI.
+#
+# [*statsd*]
+#   statsd host:port
+#
+# [*deployment_user*]
+#   scap deployment user
+#
+class superset(
+    $port              = 9080,
+    $database_uri      = 'sqlite:////var/lib/superset/superset.db',
+    $workers           = 4,
+    $admin_user        = 'admin',
+    $admin_password    = 'admin',
+    $secret_key        = 'not_really_a_secret_key',
+    $password_mapping  = undef,
+    $statsd            = undef,
+    $deployment_user   = 'analytics_deploy',
+) {
+    requires_os('debian >= jessie')
+    require_package('python', 'virtualenv', 'firejail')
+
+    $deployment_dir = '/srv/deployment/analytics/superset/deploy'
+    $virtualenv_dir = '/srv/deployment/analytics/superset/venv'
+
+    # superset runs gunicorn with gevent, use debian provided python-gevent.
+    require_package('python-gevent')
+
+    scap::target { 'analytics/superset/deploy':
+        deploy_user  => $deployment_user,
+        service_name => 'superset',
+    }
+
+    group { 'superset':
+        ensure => present,
+        system => true,
+    }
+
+    user { 'superset':
+        gid        => 'superset',
+        shell      => '/bin/bash',
+        system     => true,
+        managehome => true,
+        home       => '/var/lib/superset',
+        require    => Group['superset'],
+    }
+
+    file { '/etc/firejail/superset.profile':
+        ensure => 'present',
+        owner  => 'root',
+        group  => 'root',
+        mode   => '0444',
+        source => 'puppet:///modules/superset/superset.profile.firejail',
+    }
+
+    file { '/etc/superset':
+        ensure => 'directory',
+        owner  => 'root',
+        group  => 'root',
+        mode   => '0755',
+    }
+
+    file { '/etc/superset/gunicorn_config.py':
+        ensure  => 'present',
+        owner   => 'root',
+        group   => 'superset',
+        mode    => '0444',
+        content => template('superset/gunicorn_config.py.erb'),
+    }
+
+    file { '/etc/superset/superset_config.py':
+        ensure  => 'present',
+        owner   => 'root',
+        group   => 'superset',
+        mode    => '0440',
+        content => template('superset/superset_config.py.erb'),
+    }
+
+    # This will create tables in the superset database and add the web GUI 
admin user.
+    exec { 'init_superset':
+        command     => "${deployment_dir}/init_superset.sh ${admin_user} 
${admin_password}",
+        # Don't run init_superset.sh if superset database exists.
+        unless      => "${virtualenv_dir}/bin/python 
${deployment_dir}/superset_database_exists.py ${database_uri}",
+        user        => 'superset',
+        # Set PYTHONPATH to read superset_config.py
+        environment => ['PYTHONPATH=/etc/superset', 
'SUPERSET_HOME=/var/lib/superset'],
+        require     => [
+            Scap::Target['analytics/superset/deploy'],
+            File['/etc/superset/superset_config.py'],
+        ],
+    }
+
+    systemd::syslog { 'superset':
+        readable_by => 'all',
+        base_dir    => '/var/log',
+        group       => 'root',
+    }
+
+    systemd::service { 'superset':
+        ensure  => 'present',
+        content => systemd_template('superset'),
+        restart => true,
+        require => [
+            File['/etc/firejail/superset.profile'],
+            File['/etc/superset/gunicorn_config.py'],
+            Exec['init_superset'],
+            Systemd::Syslog['superset'],
+        ],
+    }
+}
diff --git a/modules/superset/templates/gunicorn_config.py.erb 
b/modules/superset/templates/gunicorn_config.py.erb
new file mode 100644
index 0000000..351cb24
--- /dev/null
+++ b/modules/superset/templates/gunicorn_config.py.erb
@@ -0,0 +1,7 @@
+bind = '0.0.0.0:<%= @port %>'
+workers = <%= @workers %>
+worker_class = 'gevent'
+timeout = 120
+<% if @statsd -%>
+statsd_host = '<%= @statsd %>'
+<% end -%>
diff --git a/modules/superset/templates/initscripts/superset.systemd.erb 
b/modules/superset/templates/initscripts/superset.systemd.erb
new file mode 100644
index 0000000..c6354f6
--- /dev/null
+++ b/modules/superset/templates/initscripts/superset.systemd.erb
@@ -0,0 +1,27 @@
+# NOTE: This file is managed by Puppet.
+# Systemd unit for the AirBnB Superset UI
+[Unit]
+Description="superset service"
+After=network.target
+
+[Service]
+User=superset
+Group=superset
+
+# /etc/superset contains superset_config.py, which will be used if it is in 
PYTHONPATH.
+Environment="PYTHONPATH=/etc/superset"
+Environment="SUPERSET_HOME=/var/lib/superset"
+
+Restart=always
+RestartSec=2s
+# wait 60 seconds for a graceful restart before killing the master
+TimeoutStopSec=60
+WorkingDirectory=<%= @deployment_dir %>
+ExecStart=/usr/bin/firejail --profile=/etc/firejail/superset.profile -- <%= 
@virtualenv_dir %>/bin/gunicorn \
+    --config /etc/superset/gunicorn_config.py \
+    superset:app
+
+SyslogIdentifier=superset
+
+[Install]
+WantedBy=multi-user.target
diff --git a/modules/superset/templates/superset_config.py.erb 
b/modules/superset/templates/superset_config.py.erb
new file mode 100644
index 0000000..c7f3772
--- /dev/null
+++ b/modules/superset/templates/superset_config.py.erb
@@ -0,0 +1,37 @@
+# NOTE: This file is managed by Puppet.
+
+#---------------------------------------------------------
+# Flask App Builder configuration
+#---------------------------------------------------------
+# Your App secret key
+SECRET_KEY = '<%= @secret_key %>'
+
+# The SQLAlchemy connection string to your database backend
+# This connection defines the path to the database that stores your
+# superset metadata (slices, connections, tables, dashboards, ...).
+# Note that the connection information to connect to the datasources
+# you want to explore are managed directly in the web UI
+SQLALCHEMY_DATABASE_URI = '<%= @database_uri %>'
+
+
+<%
+# If @password_mapping is given, output a python dict
+# mapping sqlalchemy URIs to passwords.  Then create
+# a function that returns password given the uri, and
+# assign that to SQLALCHEMY_CUSTOM_PASSWORD_STORE.
+#
+# This allows for configuration of databases in the
+# superset GUI, without having to enter passwords through it.
+#
+if @password_mapping
+-%>
+password_mapping = {
+<% @password_mapping.keys.sort do |uri| -%>
+    '<%= uri %>': '<%= @password_mapping[uri] %>',
+<% end -%>
+}
+def lookup_password(uri):
+    return password_mapping.get(uri, None)
+SQLALCHEMY_CUSTOM_PASSWORD_STORE = lookup_password
+
+<% end -%>

-- 
To view, visit https://gerrit.wikimedia.org/r/392978
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ib63b35e409ba4c8fbc77f342220f1f4c4f6fecea
Gerrit-PatchSet: 14
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Ottomata <[email protected]>
Gerrit-Reviewer: Elukey <[email protected]>
Gerrit-Reviewer: Ottomata <[email protected]>
Gerrit-Reviewer: Volans <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to