feat: add jupyterhub role

- add nodejs module to use npm package provider
- add jupyterhub role
- add class to configure the jupyterhub instance
- add ldap groups
- add nginx simpleproxy
This commit is contained in:
Ben Vincent 2024-11-10 13:05:53 +11:00
parent 09a448ea52
commit 159d66af18
7 changed files with 239 additions and 0 deletions

View File

@ -42,6 +42,7 @@ mod 'puppet-filemapper', '4.0.0'
mod 'puppet-letsencrypt', '11.0.0'
mod 'puppet-rundeck', '9.1.0'
mod 'puppet-redis', '11.0.0'
mod 'puppet-nodejs', '11.0.0'
# other
mod 'ghoneycutt-puppet', '3.3.0'

View 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

View File

@ -63,6 +63,7 @@ glauth::users:
- 20018
- 20023
- 20024
- 20025
loginshell: '/bin/bash'
homedir: '/home/benvin'
passsha256: 'd2434f6b4764ef75d5b7b96a876a32deedbd6aa726a109c3f32e823ca66f604a'
@ -294,3 +295,9 @@ glauth::groups:
vault_admin:
group_name: 'vault_admin'
gidnumber: 20024
jupyterhub_admin:
group_name: 'jupyterhub_admin'
gidnumber: 20025
jupyterhub_user:
group_name: 'jupyterhub_user'
gidnumber: 20026

View 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}"],
#}
}
}

View 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 %>

View 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

View 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
}
}