1{ config, lib, pkgs, ... }:
2
3let
4 cfg = config.services.openvscode-server;
5 defaultUser = "openvscode-server";
6 defaultGroup = defaultUser;
7in {
8 options = {
9 services.openvscode-server = {
10 enable = lib.mkEnableOption (lib.mdDoc "openvscode-server");
11
12 package = lib.mkPackageOptionMD pkgs "openvscode-server" { };
13
14 extraPackages = lib.mkOption {
15 default = [ ];
16 description = lib.mdDoc ''
17 Additional packages to add to the openvscode-server {env}`PATH`.
18 '';
19 example = lib.literalExpression "[ pkgs.go ]";
20 type = lib.types.listOf lib.types.package;
21 };
22
23 extraEnvironment = lib.mkOption {
24 type = lib.types.attrsOf lib.types.str;
25 description = lib.mdDoc ''
26 Additional environment variables to pass to openvscode-server.
27 '';
28 default = { };
29 example = { PKG_CONFIG_PATH = "/run/current-system/sw/lib/pkgconfig"; };
30 };
31
32 extraArguments = lib.mkOption {
33 default = [ ];
34 description = lib.mdDoc ''
35 Additional arguments to pass to openvscode-server.
36 '';
37 example = lib.literalExpression ''[ "--log=info" ]'';
38 type = lib.types.listOf lib.types.str;
39 };
40
41 host = lib.mkOption {
42 default = "localhost";
43 description = lib.mdDoc ''
44 The host name or IP address the server should listen to.
45 '';
46 type = lib.types.str;
47 };
48
49 port = lib.mkOption {
50 default = 3000;
51 description = lib.mdDoc ''
52 The port the server should listen to. If 0 is passed a random free port is picked. If a range in the format num-num is passed, a free port from the range (end inclusive) is selected.
53 '';
54 type = lib.types.port;
55 };
56
57 user = lib.mkOption {
58 default = defaultUser;
59 example = "yourUser";
60 description = lib.mdDoc ''
61 The user to run openvscode-server as.
62 By default, a user named `${defaultUser}` will be created.
63 '';
64 type = lib.types.str;
65 };
66
67 group = lib.mkOption {
68 default = defaultGroup;
69 example = "yourGroup";
70 description = lib.mdDoc ''
71 The group to run openvscode-server under.
72 By default, a group named `${defaultGroup}` will be created.
73 '';
74 type = lib.types.str;
75 };
76
77 extraGroups = lib.mkOption {
78 default = [ ];
79 description = lib.mdDoc ''
80 An array of additional groups for the `${defaultUser}` user.
81 '';
82 example = [ "docker" ];
83 type = lib.types.listOf lib.types.str;
84 };
85
86 withoutConnectionToken = lib.mkOption {
87 default = false;
88 description = lib.mdDoc ''
89 Run without a connection token. Only use this if the connection is secured by other means.
90 '';
91 example = true;
92 type = lib.types.bool;
93 };
94
95 socketPath = lib.mkOption {
96 default = null;
97 example = "/run/openvscode/socket";
98 description = lib.mdDoc ''
99 The path to a socket file for the server to listen to.
100 '';
101 type = lib.types.nullOr lib.types.str;
102 };
103
104 userDataDir = lib.mkOption {
105 default = null;
106 description = lib.mdDoc ''
107 Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.
108 '';
109 type = lib.types.nullOr lib.types.str;
110 };
111
112 serverDataDir = lib.mkOption {
113 default = null;
114 description = lib.mdDoc ''
115 Specifies the directory that server data is kept in.
116 '';
117 type = lib.types.nullOr lib.types.str;
118 };
119
120 extensionsDir = lib.mkOption {
121 default = null;
122 description = lib.mdDoc ''
123 Set the root path for extensions.
124 '';
125 type = lib.types.nullOr lib.types.str;
126 };
127
128 telemetryLevel = lib.mkOption {
129 default = "off";
130 example = "crash";
131 description = lib.mdDoc ''
132 Sets the initial telemetry level. Valid levels are: 'off', 'crash', 'error' and 'all'.
133 '';
134 type = lib.types.str;
135 };
136
137 connectionToken = lib.mkOption {
138 default = null;
139 example = "secret-token";
140 description = lib.mdDoc ''
141 A secret that must be included with all requests.
142 '';
143 type = lib.types.nullOr lib.types.str;
144 };
145
146 connectionTokenFile = lib.mkOption {
147 default = null;
148 description = lib.mdDoc ''
149 Path to a file that contains the connection token.
150 '';
151 type = lib.types.nullOr lib.types.str;
152 };
153
154 };
155 };
156
157 config = lib.mkIf cfg.enable {
158 systemd.services.openvscode-server = {
159 description = "OpenVSCode server";
160 wantedBy = [ "multi-user.target" ];
161 after = [ "network-online.target" ];
162 path = cfg.extraPackages;
163 environment = cfg.extraEnvironment;
164 serviceConfig = {
165 ExecStart = ''
166 ${lib.getExe cfg.package} \
167 --accept-server-license-terms \
168 --host=${cfg.host} \
169 --port=${toString cfg.port} \
170 '' + lib.optionalString (cfg.telemetryLevel == true) ''
171 --telemetry-level=${cfg.telemetryLevel} \
172 '' + lib.optionalString (cfg.withoutConnectionToken == true) ''
173 --without-connection-token \
174 '' + lib.optionalString (cfg.socketPath != null) ''
175 --socket-path=${cfg.socketPath} \
176 '' + lib.optionalString (cfg.userDataDir != null) ''
177 --user-data-dir=${cfg.userDataDir} \
178 '' + lib.optionalString (cfg.serverDataDir != null) ''
179 --server-data-dir=${cfg.serverDataDir} \
180 '' + lib.optionalString (cfg.extensionsDir != null) ''
181 --extensions-dir=${cfg.extensionsDir} \
182 '' + lib.optionalString (cfg.connectionToken != null) ''
183 --connection-token=${cfg.connectionToken} \
184 '' + lib.optionalString (cfg.connectionTokenFile != null) ''
185 --connection-token-file=${cfg.connectionTokenFile} \
186 '' + lib.escapeShellArgs cfg.extraArguments;
187 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
188 RuntimeDirectory = cfg.user;
189 User = cfg.user;
190 Group = cfg.group;
191 Restart = "on-failure";
192 };
193 };
194
195 users.users."${cfg.user}" = lib.mkMerge [
196 (lib.mkIf (cfg.user == defaultUser) {
197 isNormalUser = true;
198 description = "openvscode-server user";
199 inherit (cfg) group;
200 })
201 {
202 packages = cfg.extraPackages;
203 inherit (cfg) extraGroups;
204 }
205 ];
206
207 users.groups."${defaultGroup}" = lib.mkIf (cfg.group == defaultGroup) { };
208 };
209
210 meta.maintainers = [ lib.maintainers.drupol ];
211}