diff mbox series

[bug#50708] gnu: web: Add jupyter-service

Message ID cc9534d6-a448-9c30-e851-8dae9ff0eec6@gmail.com
State New
Headers show
Series [bug#50708] gnu: web: Add jupyter-service | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch fail View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch fail View Laminar job
cbaines/issue success View issue

Commit Message

Jesse Gibbons Sept. 23, 2021, 2:22 a.m. UTC
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 <gib19014@byui.edu>
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(+)

Comments

Xinglu Chen Sept. 28, 2021, 7:17 p.m. UTC | #1
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 <gib19014@byui.edu>
> 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 <arunisaac@systemreboot.net>
>  ;;; Copyright © 2020 Oleg Pykhalov <go.wigust@gmail.com>
>  ;;; Copyright © 2020, 2021 Alexandru-Sergiu Marton <brown121407@posteo.ro>
> +;;; Copyright © 2020, 2021 Jesse Gibbons <jgibbons2357+guix@gmail.com>
>  ;;;
>  ;;; 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> 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
  (($ <jupyter-configuration> _ _ 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
diff mbox series

Patch

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
+@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 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.
+
+@table @asis
+@item @code{jupyter-package} (default: @code{jupyter})
+The jupyter package to use.
+
+
+@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.
+
+@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).
+
+@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.
+
+@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 <arunisaac@systemreboot.net>
 ;;; Copyright © 2020 Oleg Pykhalov <go.wigust@gmail.com>
 ;;; Copyright © 2020, 2021 Alexandru-Sergiu Marton <brown121407@posteo.ro>
+;;; Copyright © 2020, 2021 Jesse Gibbons <jgibbons2357+guix@gmail.com>
 ;;;
 ;;; 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
+(define-public default-jupyter-config "#")
+
+(define-record-type* <jupyter-configuration> 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))
+                     (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)))
+
+;;;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)))
+                     #: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."))))
+
+(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)))
+
+(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.")
+    (default-value (jupyter-configuration))))