On Wed, Sep 22 2021, Jesse wrote: > Attached is yet another updated patch fixing a mistake in the added > documentation. > > On 9/21/21 7:26 PM, Jesse wrote: >> Attached is an updated patch. > From d264da0811480a8d2acd5e73f58d320e15bfa9f3 Mon Sep 17 00:00:00 2001 > From: Jesse > Date: Mon, 20 Sep 2021 16:01:22 -0600 > Subject: [PATCH] gnu: web: Add jupyter-service > > * gnu/services/web.scm (gitile-service-type): New variable. > * doc/guix.texi (Version Control Services): Document it. > --- > doc/guix.texi | 52 +++++++++++++++++++ > gnu/services/web.scm | 120 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 172 insertions(+) It would also be good to have a test for the service. You can look at at (gnu tests ...) modules for some inspiration. > diff --git a/doc/guix.texi b/doc/guix.texi > index 6436e83a7c..0f8aaca413 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -26197,6 +26197,58 @@ The file which should store the logging output of Agate. > @end table > @end deftp > > +@cindex jupyter > +The Jupyter Notebook is a web application that allows you to create > +and share documents that contain live code, equations, visualizations > +and explanatory text. Uses include: data cleaning and transformation, > +numerical simulation, statistical modeling, machine learning and much > +more. > + > +@deffn (Scheme Variable) jupyter-service-type > +This is the type of the agate service, whose value should be an Agate service? The Jupyter service doesn’t seem to use Agate anywhere. > +@code{jupyter-service-type} object, as in this example: > + > +@lisp > +(service jupyter-service-type > + (jupyter-configuration > + (log-file "/var/log/jupyter.log") > + (server-config > + (kernels > + (list jupyter-guile-kernel))))) > + > +@end lisp The indentation looks incorrect. Also the trailing newline isn’t necessary. Something like --8<---------------cut here---------------start------------->8--- (service jupyter-service-type (jupyter-configuration (log-file "/var/log/jupyter.log") (server-config (kernels (list jupyter-guile-kernel))))) --8<---------------cut here---------------end--------------->8--- > +The example above tells the the Jupyter service to provide the > +@code{jupyter-guile-kernel} as an optional kernel. > +@end deffn > + > +@deftp {Data Type} jupyter-configuration > +Data type representing the configuration of Agate. s/Agate/Jupyter/ ? > +@table @asis > +@item @code{jupyter-package} (default: @code{jupyter}) > +The jupyter package to use. “jupyter” should be capitalized. > + > + > +@item @code{kernels} (default: @code{'()} > +A list of kernel packages to use with the jupyter service. > + > +@item @code{root-dir} (default: @file{"/var/lib/jupyter/notebooks"}) > +The directory where the jupyter server looks for jupyter notebooks. > + > +@item @code{log-file} (default: @code{#f}) > +The location of the log file. If #f is given, no log is produced. ^ There should be two spaces after a period. > +@item @code{shell} (default: @code{(file-append bash "/bin/bash")} > +The location of the shell used when starting a web terminal (if it is configured to allow terminals). Line should be kept at <=80 chars. > +@item @code{server-config} (default: @code{#f}) > +A file contianing the jupyter server's config file. If @code{#f} is given, an empty file is produced, and the default settings are used. Likewise (<=80 line length). What exactly does “A file” mean, do you mean “file-like objects” (see “8.10 G-Expressions” in the manual)? The example config doesn’t seem to provide anything “A file” either --8<---------------cut here---------------start------------->8--- (service jupyter-service-type (jupyter-configuration (log-file "/var/log/jupyter.log") (server-config (kernels (list jupyter-guile-kernel))))) --8<---------------cut here---------------end--------------->8--- ‘kernels’ doesn’t seem to be a procedure or macro, but rather a field in the ‘jupyter-configuration’ record, so the example needs to be fixed as well. > + > +@end table > +@end deftp > + > + > @node Certificate Services > @subsection Certificate Services > > diff --git a/gnu/services/web.scm b/gnu/services/web.scm > index 6a093cf4e4..2d2946f7a7 100644 > --- a/gnu/services/web.scm > +++ b/gnu/services/web.scm > @@ -15,6 +15,7 @@ > ;;; Copyright © 2020 Arun Isaac > ;;; Copyright © 2020 Oleg Pykhalov > ;;; Copyright © 2020, 2021 Alexandru-Sergiu Marton > +;;; Copyright © 2020, 2021 Jesse Gibbons > ;;; > ;;; This file is part of GNU Guix. > ;;; > @@ -41,11 +42,13 @@ > #:use-module (gnu system shadow) > #:use-module (gnu packages admin) > #:use-module (gnu packages base) > + #:use-module (gnu packages bash) > #:use-module (gnu packages databases) > #:use-module (gnu packages web) > #:use-module (gnu packages patchutils) > #:use-module (gnu packages php) > #:use-module (gnu packages python) > + #:use-module (gnu packages python-xyz) > #:use-module (gnu packages gnupg) > #:use-module (gnu packages guile) > #:use-module (gnu packages logging) > @@ -91,6 +94,8 @@ > > httpd-service-type > > + jupyter-configuration > + > nginx-configuration > nginx-configuration? > nginx-configuration-nginx > @@ -1994,3 +1999,118 @@ root=/srv/gemini > (service-extension shepherd-root-service-type > agate-shepherd-service))) > (default-value (agate-configuration)))) > + > + > +;;; Jupyter configuration > +;;; Jupyter server configuration > +;;; -> includes a list of kernels to allow in the jupyter server > +;;; -> includes a list of configuration options specifically for the jupyter server > +;;; --> These options can be concatenated to a python file > +;;; --> Nested alist > +;;; ---> '((NotebookApp (allow-remote-access #t))) -> "c.NotebookApp.allow_remote_access = True" > +;;; -> Include some settings specifying how to run the daemon > +;;; --> location of log file > +;;; --> If a console should be allowed, the location of the shell to be used. > +;;; --> The package containing the jupyter server itself, default jupyter What do these arrows mean? Also, keep lines <=80 chars wide. > +(define-public default-jupyter-config "#") Does the default config have to contain a “#”, can’t it just be an empty string? > + > +(define-record-type* jupyter-configuration > + this-jupyter-configuration jupyter-configuration? > + (jupyter-package jupyter-configuration-jupyter-package > + (default jupyter)) > + (kernels jupyter-configuration-kernels > + (default '())) > + (root-dir jupyter-configuration-root-dir > + (default "/var/lib/jupyter/notebooks")) > + (log-file jupyter-configuration-log-file > + (default #f)) I think it would be good to have a log file by default. > + (shell jupyter-configuration-shell > + (default (file-append bash "/bin/bash"))) > + (server-config jupyter-configuration-server-config > + (default #f))); TODO: Make configuration DSL. > + > + > +(define (search-path-string search-path-pair) > + (string-append (search-path-specification-variable (car search-path-pair)) > + "=" > + (cdr search-path-pair))) Prefer ‘match’ over ‘car’ and ‘cdr’. > + > +;;;TODO: Add actions to list jupyter servers, change passwords, etc. > +(define (jupyter-shepherd-service config) > + (list (shepherd-service > + (provision '(jupyter)) ;TODO: Add magic to allow multiple Jupyter servers > + (requirement '(loopback)) > + (start #~(make-forkexec-constructor > + (list "/run/current-system/profile/bin/jupyter" > + "notebook" > + (string-append "--config=" > + #$(or (jupyter-configuration-server-config config) > + (plain-file "jupyter_notebook_config.py" > + default-jupyter-config)) > + #$(jupyter-configuration-root-dir config))) Prefer ‘match’ instead of using accessor procedures. Something like --8<---------------cut here---------------start------------->8--- (match config (($ _ _ root-dir log-file _ server-config) (list (shepherd-service ...)))) --8<---------------cut here---------------end--------------->8--- > + #:user "jupyter" > + #:group "jupyter" > + #:environment-variables ; TODO use search-paths magic instead of hard-coding these things. > + (list "GI_TYPELIB_PATH=/run/current-system/profile/lib/girepository-1.0" > + "GUILE_LOAD_COMPILED_PATH=/run/current-system/profile/lib/guile/3.0/site-ccache:/run/current-system/profile/share/guile/site/3.0" > + "GUILE_LOAD_PATH=/run/current-system/profile/share/guile/site/3.0" > + "HOME=/var/lib/jupyter" > + "JUPYTER_PATH=/run/current-system/profile/share/jupyter" > + "PATH=/run/current-system/profile/bin:/run/current-system/profile/sbin" > + "PYTHONPATH=/run/current-system/profile/lib/python3.8/site-packages" > + "R_LIBS_SITE=/run/current-system/profile/site-library/" > + "TEXMF=/run/current-system/profile/share/texmf-dist" > + "TEXMFCNF=/run/current-system/profile//share/texmf-dist/web2c" > + "XDG_DATA_DIRS=/run/current-system/profile/share") > + > + #:directory #$(jupyter-configuration-root-dir config) > + #:log-file #$(jupyter-configuration-log-file config))) > + (stop #~(make-kill-destructor)) > + (documentation "Runs a Jupyter Notebook server. A Jupyter Notebook is a web application that allows you to create and share documents that contain live code, equations, visualizations, and explanatory text.")))) Watch the line length! :-) > + > +(define (jupyter-account config) > + (list > + (user-account > + (name "jupyter") > + (group "jupyter") > + (comment "Jupyter Notebook Server") > + (home-directory "/var/lib/jupyter") > + (shell (jupyter-configuration-shell config)) > + (system? #t)) > + (user-group > + (name "jupyter") > + (system? #t)))) > + > +(define (jupyter-profile config) > + (cons* > + (jupyter-configuration-jupyter-package config) > + (jupyter-configuration-kernels config))) Prefer ‘match’ instead of using accessor procedures. > + > +(define (jupyter-activation config) > + #~(begin > + (let ((root-dir #$(jupyter-configuration-root-dir config)) > + (pw (getpwnam "jupyter"))) > + (unless (file-exists? root-dir) > + (mkdir root-dir) > + (chown root-dir (passwd:uid pw) > + (passwd:gid pw)) > + (chmod root-dir #o700))))) > + > +;;; Jupyter service type > +;;; -> Information vital to settinng up the server, like the port and accepted parameters > +;;; -> list of kernels considered permissible. > +;;; -> a shepherd service extension that runs the jupyter server > +;;; --> shepherd service to list the running servers, set the password, etc. > +;;; --> Make a log file only readable by root? > +;;; -> an accounts service extension describing the user that runs the accounts > +;;; --> group "jupyter" > +(define-public jupyter-service-type > + (service-type > + (name "jupyter") > + (extensions (list > + (service-extension shepherd-root-service-type jupyter-shepherd-service) > + (service-extension account-service-type jupyter-account) > + (service-extension activation-service-type jupyter-activation) > + (service-extension profile-service-type jupyter-profile))) > + (description "Runs a Jupyter Notebook server. A Jupyter Notebook is a web application that allows you to create and share documents that contain live code, equations, visualizations, and explanatory text.") Keep lines <=80 chars, and use double-spacing. > + (default-value (jupyter-configuration)))) > -- > 2.33.0