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