handheld-daemon-ui: 3.2.3 -> 3.3.0 (#361609)
[NixPkgs.git] / nixos / modules / services / development / jupyter / default.nix
blobd9687fdbf7139eac6e52d700ae892e4ee0f4d79d
1 { config, lib, pkgs, ... }:
2 let
4   cfg = config.services.jupyter;
6   package = cfg.package;
8   kernels = (pkgs.jupyter-kernel.create  {
9     definitions = if cfg.kernels != null
10       then cfg.kernels
11       else  pkgs.jupyter-kernel.default;
12   });
14   notebookConfig = pkgs.writeText "jupyter_config.py" ''
15     ${cfg.notebookConfig}
17     c.NotebookApp.password = ${cfg.password}
18   '';
20 in {
21   meta.maintainers = with lib.maintainers; [ aborsu ];
23   options.services.jupyter = {
24     enable = lib.mkEnableOption "Jupyter development server";
26     ip = lib.mkOption {
27       type = lib.types.str;
28       default = "localhost";
29       description = ''
30         IP address Jupyter will be listening on.
31       '';
32     };
34     # NOTE: We don't use top-level jupyter because we don't
35     # want to pass in JUPYTER_PATH but use .environment instead,
36     # saving a rebuild.
37     package = lib.mkPackageOption pkgs [ "python3" "pkgs" "notebook" ] { };
39     command = lib.mkOption {
40       type = lib.types.str;
41       default = "jupyter-notebook";
42       example = "jupyter-lab";
43       description = ''
44         Which command the service runs. Note that not all jupyter packages
45         have all commands, e.g. jupyter-lab isn't present in the default package.
46        '';
47     };
49     port = lib.mkOption {
50       type = lib.types.port;
51       default = 8888;
52       description = ''
53         Port number Jupyter will be listening on.
54       '';
55     };
57     notebookDir = lib.mkOption {
58       type = lib.types.str;
59       default = "~/";
60       description = ''
61         Root directory for notebooks.
62       '';
63     };
65     user = lib.mkOption {
66       type = lib.types.str;
67       default = "jupyter";
68       description = ''
69         Name of the user used to run the jupyter service.
70         For security reason, jupyter should really not be run as root.
71         If not set (jupyter), the service will create a jupyter user with appropriate settings.
72       '';
73       example = "aborsu";
74     };
76     group = lib.mkOption {
77       type = lib.types.str;
78       default = "jupyter";
79       description = ''
80         Name of the group used to run the jupyter service.
81         Use this if you want to create a group of users that are able to view the notebook directory's content.
82       '';
83       example = "users";
84     };
86     password = lib.mkOption {
87       type = lib.types.str;
88       description = ''
89         Password to use with notebook.
90         Can be generated using:
91           In [1]: from notebook.auth import passwd
92           In [2]: passwd('test')
93           Out[2]: 'sha1:1b961dc713fb:88483270a63e57d18d43cf337e629539de1436ba'
94           NOTE: you need to keep the single quote inside the nix string.
95         Or you can use a python oneliner:
96           "open('/path/secret_file', 'r', encoding='utf8').read().strip()"
97         It will be interpreted at the end of the notebookConfig.
98       '';
99       example = "'sha1:1b961dc713fb:88483270a63e57d18d43cf337e629539de1436ba'";
100     };
102     notebookConfig = lib.mkOption {
103       type = lib.types.lines;
104       default = "";
105       description = ''
106         Raw jupyter config.
107       '';
108     };
110     kernels = lib.mkOption {
111       type = lib.types.nullOr (lib.types.attrsOf(lib.types.submodule (import ./kernel-options.nix {
112         inherit lib pkgs;
113       })));
115       default = null;
116       example = lib.literalExpression ''
117         {
118           python3 = let
119             env = (pkgs.python3.withPackages (pythonPackages: with pythonPackages; [
120                     ipykernel
121                     pandas
122                     scikit-learn
123                   ]));
124           in {
125             displayName = "Python 3 for machine learning";
126             argv = [
127               "''${env.interpreter}"
128               "-m"
129               "ipykernel_launcher"
130               "-f"
131               "{connection_file}"
132             ];
133             language = "python";
134             logo32 = "''${env.sitePackages}/ipykernel/resources/logo-32x32.png";
135             logo64 = "''${env.sitePackages}/ipykernel/resources/logo-64x64.png";
136             extraPaths = {
137               "cool.txt" = pkgs.writeText "cool" "cool content";
138             };
139           };
140         }
141       '';
142       description = ''
143         Declarative kernel config.
145         Kernels can be declared in any language that supports and has the required
146         dependencies to communicate with a jupyter server.
147         In python's case, it means that ipykernel package must always be included in
148         the list of packages of the targeted environment.
149       '';
150     };
151   };
153   config = lib.mkMerge [
154     (lib.mkIf cfg.enable  {
155       systemd.services.jupyter = {
156         description = "Jupyter development server";
158         after = [ "network.target" ];
159         wantedBy = [ "multi-user.target" ];
161         # TODO: Patch notebook so we can explicitly pass in a shell
162         path = [ pkgs.bash ]; # needed for sh in cell magic to work
164         environment = {
165           JUPYTER_PATH = toString kernels;
166         };
168         serviceConfig = {
169           Restart = "always";
170           ExecStart = ''${package}/bin/${cfg.command} \
171             --no-browser \
172             --ip=${cfg.ip} \
173             --port=${toString cfg.port} --port-retries 0 \
174             --notebook-dir=${cfg.notebookDir} \
175             --NotebookApp.config_file=${notebookConfig}
176           '';
177           User = cfg.user;
178           Group = cfg.group;
179           WorkingDirectory = "~";
180         };
181       };
182     })
183     (lib.mkIf (cfg.enable && (cfg.group == "jupyter")) {
184       users.groups.jupyter = {};
185     })
186     (lib.mkIf (cfg.enable && (cfg.user == "jupyter")) {
187       users.extraUsers.jupyter = {
188         inherit (cfg) group;
189         home = "/var/lib/jupyter";
190         createHome = true;
191         isSystemUser = true;
192         useDefaultShell = true; # needed so that the user can start a terminal.
193       };
194     })
195   ];