Merge pull request 'feat: add jupyterhub role' (#173) from neoloc/jupyterhub into develop
Reviewed-on: https://git.query.consul/unkinben/puppet-prod/pulls/173
This commit is contained in:
commit
c6bdae5790
@ -42,6 +42,7 @@ mod 'puppet-filemapper', '4.0.0'
|
|||||||
mod 'puppet-letsencrypt', '11.0.0'
|
mod 'puppet-letsencrypt', '11.0.0'
|
||||||
mod 'puppet-rundeck', '9.1.0'
|
mod 'puppet-rundeck', '9.1.0'
|
||||||
mod 'puppet-redis', '11.0.0'
|
mod 'puppet-redis', '11.0.0'
|
||||||
|
mod 'puppet-nodejs', '11.0.0'
|
||||||
|
|
||||||
# other
|
# other
|
||||||
mod 'ghoneycutt-puppet', '3.3.0'
|
mod 'ghoneycutt-puppet', '3.3.0'
|
||||||
|
|||||||
45
hieradata/roles/apps/jupyter/hub.yaml
Normal file
45
hieradata/roles/apps/jupyter/hub.yaml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
profiles::packages::include:
|
||||||
|
python3.12: {}
|
||||||
|
python3.12-pip: {}
|
||||||
|
|
||||||
|
hiera_include:
|
||||||
|
- profiles::nginx::simpleproxy
|
||||||
|
|
||||||
|
# manage a simple nginx reverse proxy
|
||||||
|
profiles::nginx::simpleproxy::nginx_vhost: 'jupyterhub.query.consul'
|
||||||
|
profiles::nginx::simpleproxy::nginx_aliases:
|
||||||
|
- jupyterhub.service.consul
|
||||||
|
- jupyterhub.query.consul
|
||||||
|
- "jupyterhub.service.%{facts.country}-%{facts.region}.consul"
|
||||||
|
|
||||||
|
profiles::nginx::simpleproxy::proxy_port: 8000
|
||||||
|
profiles::nginx::simpleproxy::proxy_path: '/'
|
||||||
|
nginx::client_max_body_size: 20M
|
||||||
|
|
||||||
|
# additional altnames
|
||||||
|
profiles::pki::vault::alt_names:
|
||||||
|
- jupyterhub.service.consul
|
||||||
|
- jupyterhub.query.consul
|
||||||
|
- "jupyterhub.service.%{facts.country}-%{facts.region}.consul"
|
||||||
|
|
||||||
|
# configure consul service
|
||||||
|
consul::services:
|
||||||
|
jupyterhub:
|
||||||
|
service_name: 'jupyterhub'
|
||||||
|
tags:
|
||||||
|
- 'jupyterhub'
|
||||||
|
address: "%{facts.networking.ip}"
|
||||||
|
port: 443
|
||||||
|
checks:
|
||||||
|
- id: 'jupyterhub_http_check'
|
||||||
|
name: 'jupyterhub HTTP Check'
|
||||||
|
http: "https://%{facts.networking.fqdn}"
|
||||||
|
method: 'GET'
|
||||||
|
tls_skip_verify: true
|
||||||
|
interval: '10s'
|
||||||
|
timeout: '1s'
|
||||||
|
profiles::consul::client::node_rules:
|
||||||
|
- resource: service
|
||||||
|
segment: jupyterhub
|
||||||
|
disposition: write
|
||||||
@ -63,6 +63,7 @@ glauth::users:
|
|||||||
- 20018
|
- 20018
|
||||||
- 20023
|
- 20023
|
||||||
- 20024
|
- 20024
|
||||||
|
- 20025
|
||||||
loginshell: '/bin/bash'
|
loginshell: '/bin/bash'
|
||||||
homedir: '/home/benvin'
|
homedir: '/home/benvin'
|
||||||
passsha256: 'd2434f6b4764ef75d5b7b96a876a32deedbd6aa726a109c3f32e823ca66f604a'
|
passsha256: 'd2434f6b4764ef75d5b7b96a876a32deedbd6aa726a109c3f32e823ca66f604a'
|
||||||
@ -294,3 +295,9 @@ glauth::groups:
|
|||||||
vault_admin:
|
vault_admin:
|
||||||
group_name: 'vault_admin'
|
group_name: 'vault_admin'
|
||||||
gidnumber: 20024
|
gidnumber: 20024
|
||||||
|
jupyterhub_admin:
|
||||||
|
group_name: 'jupyterhub_admin'
|
||||||
|
gidnumber: 20025
|
||||||
|
jupyterhub_user:
|
||||||
|
group_name: 'jupyterhub_user'
|
||||||
|
gidnumber: 20026
|
||||||
|
|||||||
115
site/profiles/manifests/jupyter/jupyterhub.pp
Normal file
115
site/profiles/manifests/jupyter/jupyterhub.pp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# profiles::jupyter::jupyterhub
|
||||||
|
class profiles::jupyter::jupyterhub (
|
||||||
|
Stdlib::AbsolutePath $base_path = '/opt/jupyterhub',
|
||||||
|
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
||||||
|
Stdlib::AbsolutePath $config_path = "${base_path}/config.py",
|
||||||
|
Hash $vault_config = {},
|
||||||
|
String $owner = 'jupyterhub',
|
||||||
|
String $group = 'jupyterhub',
|
||||||
|
Boolean $systempkgs = false,
|
||||||
|
String $version = '3.12',
|
||||||
|
Array[String[1]] $packages = [
|
||||||
|
'jupyterhub',
|
||||||
|
'dockerspawner',
|
||||||
|
'jupyterhub-ldapauthenticator',
|
||||||
|
],
|
||||||
|
String $ldap_server_address = 'ldap://ldap.service.consul',
|
||||||
|
String $ldap_bind_dn_template = 'cn={username},ou=people,ou=users,dc=main,dc=unkin,dc=net',
|
||||||
|
Boolean $ldap_use_ssl = false,
|
||||||
|
Array $ldap_allowed_groups = ['ou=jupyterhub_user,ou=groups,dc=main,dc=unkin,dc=net'],
|
||||||
|
Array $ldap_admin_groups = ['ou=jupyterhub_admin,ou=groups,dc=main,dc=unkin,dc=net'],
|
||||||
|
){
|
||||||
|
|
||||||
|
# ensure nodejs:20 is installed
|
||||||
|
package { 'nodejs_module':
|
||||||
|
ensure => '20',
|
||||||
|
name => 'nodejs',
|
||||||
|
provider => 'dnfmodule',
|
||||||
|
enable_only => true,
|
||||||
|
}
|
||||||
|
-> package { 'nodejs':
|
||||||
|
ensure => 'installed',
|
||||||
|
provider => 'dnf',
|
||||||
|
}
|
||||||
|
-> package { 'npm':
|
||||||
|
ensure => 'installed',
|
||||||
|
provider => 'dnf',
|
||||||
|
}
|
||||||
|
-> package { 'configurable-http-proxy':
|
||||||
|
ensure => installed,
|
||||||
|
provider => 'npm',
|
||||||
|
}
|
||||||
|
|
||||||
|
# ensure python3.12 is installed
|
||||||
|
if $::facts['python3_version'] {
|
||||||
|
|
||||||
|
$python_version = $version ? {
|
||||||
|
'system' => $::facts['python3_version'],
|
||||||
|
default => $version,
|
||||||
|
}
|
||||||
|
|
||||||
|
# ensure the base_path exists
|
||||||
|
file { $base_path:
|
||||||
|
ensure => directory,
|
||||||
|
mode => '0755',
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
require => Profiles::Base::Account['jupyterhub'],
|
||||||
|
}
|
||||||
|
|
||||||
|
# create a venv
|
||||||
|
python::pyvenv { $venv_path :
|
||||||
|
ensure => present,
|
||||||
|
version => $python_version,
|
||||||
|
systempkgs => $systempkgs,
|
||||||
|
venv_dir => $venv_path,
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
require => File[$base_path],
|
||||||
|
}
|
||||||
|
|
||||||
|
# install the required pip packages
|
||||||
|
$packages.each |String $package| {
|
||||||
|
python::pip { "${venv_path}_${package}":
|
||||||
|
ensure => present,
|
||||||
|
pkgname => $package,
|
||||||
|
virtualenv => $venv_path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# create the config from a template
|
||||||
|
file { $config_path:
|
||||||
|
ensure => file,
|
||||||
|
mode => '0660',
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
content => Sensitive(template('profiles/jupyterhub/config.py.erb')),
|
||||||
|
require => Python::Pyvenv[$venv_path],
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles::base::account {$owner:
|
||||||
|
username => $owner,
|
||||||
|
uid => 1101,
|
||||||
|
gid => 1101,
|
||||||
|
groups => ['systemd-journal'],
|
||||||
|
system => true,
|
||||||
|
}
|
||||||
|
|
||||||
|
systemd::unit_file { 'jupyterhub.service':
|
||||||
|
content => template('profiles/jupyterhub/jupyterhub.service.erb'),
|
||||||
|
enable => true,
|
||||||
|
active => true,
|
||||||
|
subscribe => File[$config_path],
|
||||||
|
require => [
|
||||||
|
File[$config_path],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
## create symbolic link in $PATH
|
||||||
|
#file { "/usr/local/bin/${script_name}":
|
||||||
|
# ensure => 'link',
|
||||||
|
# target => "${base_path}/${script_name}",
|
||||||
|
# require => File["${base_path}/${script_name}"],
|
||||||
|
#}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
site/profiles/templates/jupyterhub/config.py.erb
Normal file
43
site/profiles/templates/jupyterhub/config.py.erb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# jupyterhub_config.py
|
||||||
|
|
||||||
|
from dockerspawner import DockerSpawner
|
||||||
|
import os
|
||||||
|
|
||||||
|
c = get_config()
|
||||||
|
|
||||||
|
# Basic JupyterHub settings
|
||||||
|
c.JupyterHub.bind_url = 'http://:8000'
|
||||||
|
c.JupyterHub.hub_ip = '0.0.0.0'
|
||||||
|
c.JupyterHub.hub_port = 8081
|
||||||
|
|
||||||
|
# Configure the DockerSpawner
|
||||||
|
c.JupyterHub.spawner_class = DockerSpawner
|
||||||
|
c.DockerSpawner.image = '<%= @docker_image %>'
|
||||||
|
c.DockerSpawner.network_name = '<%= @docker_network %>'
|
||||||
|
|
||||||
|
# Notebook directory and mount location
|
||||||
|
notebook_dir = '/home/jupyter/work'
|
||||||
|
c.DockerSpawner.notebook_dir = notebook_dir
|
||||||
|
|
||||||
|
# Optional: Volume mapping for user data persistence
|
||||||
|
c.DockerSpawner.volumes = {
|
||||||
|
'jupyterhub-user-{username}': notebook_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
# DockerSpawner options
|
||||||
|
c.DockerSpawner.remove = True
|
||||||
|
c.DockerSpawner.debug = True
|
||||||
|
|
||||||
|
# LDAP Authentication
|
||||||
|
c.JupyterHub.authenticator_class = 'ldapauthenticator.LDAPAuthenticator'
|
||||||
|
|
||||||
|
# LDAP Server settings
|
||||||
|
c.LDAPAuthenticator.server_address = '<%= @ldap_server_address %>'
|
||||||
|
c.LDAPAuthenticator.bind_dn_template = '<%= @ldap_bind_dn_template %>'
|
||||||
|
c.LDAPAuthenticator.use_ssl = <%= @ldap_use_ssl ? 'True' : 'False' %>
|
||||||
|
|
||||||
|
# Restrict access to a specific LDAP group
|
||||||
|
c.LDAPAuthenticator.allowed_groups = <%= @ldap_allowed_groups.to_s %>
|
||||||
|
|
||||||
|
# Set an LDAP group as admins
|
||||||
|
c.LDAPAuthenticator.admin_groups = <%= @ldap_admin_groups.to_s %>
|
||||||
16
site/profiles/templates/jupyterhub/jupyterhub.service.erb
Normal file
16
site/profiles/templates/jupyterhub/jupyterhub.service.erb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=JupyterHub
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/opt/jupyterhub/venv/bin/jupyterhub -f /opt/jupyterhub/config.py
|
||||||
|
WorkingDirectory=/opt/jupyterhub
|
||||||
|
User=<%= @owner %>
|
||||||
|
Group=<%= @group %>
|
||||||
|
|
||||||
|
Environment="PATH=/opt/jupyterhub/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
12
site/roles/manifests/apps/jupyter/hub.pp
Normal file
12
site/roles/manifests/apps/jupyter/hub.pp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# jupyterhub server profile
|
||||||
|
class roles::apps::jupyter::hub {
|
||||||
|
if $facts['firstrun'] {
|
||||||
|
include profiles::defaults
|
||||||
|
include profiles::firstrun::init
|
||||||
|
}else{
|
||||||
|
include profiles::defaults
|
||||||
|
include profiles::base
|
||||||
|
include profiles::base::datavol
|
||||||
|
include profiles::jupyter::jupyterhub
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user